use RegionGuard instead of manual call of pair enter/leave_region

This commit is contained in:
Dmitry
2022-05-08 11:26:22 +03:00
parent 233819b841
commit a4aa9329e8
47 changed files with 475 additions and 1133 deletions
+1 -11
View File
@@ -29,21 +29,11 @@ use std::{
sync::mpsc::Sender,
};
#[derive(Default, Eq, PartialEq)]
#[derive(Default, Eq, PartialEq, Visit)]
struct HistoryEntry {
work_dir: PathBuf,
}
impl Visit for HistoryEntry {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.work_dir.visit("WorkDir", visitor)?;
visitor.leave_region()
}
}
pub const HISTORY_PATH: &str = "history.bin";
pub struct Configurator {
+20 -22
View File
@@ -47,7 +47,7 @@ impl Visit for LocomotionMachine {
// new node in tree structure and makes it current so every later calls of visit
// will write data into that node, of course inner calls can call enter_region -
// visitor can manage trees of any depth.
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
// Just call visit on every field, checking the result of operation.
// For backwards compatibility you can ignore result.
@@ -55,48 +55,46 @@ impl Visit for LocomotionMachine {
// or some other generic type, inner type must implement at least Default trait plus
// some types (Arc, Mutex) adds Send, Sync - if compiler tells you that .visit method is
// not found then it is probably you missed some of required trait bounds.
self.jump_animation.visit("JumpAnimation", visitor)?;
self.walk_animation.visit("WalkAnimation", visitor)?;
self.walk_state.visit("WalkState", visitor)?;
self.jump_animation.visit("JumpAnimation", &mut region)?;
self.walk_animation.visit("WalkAnimation", &mut region)?;
self.walk_state.visit("WalkState", &mut region)?;
// Machine is an internal Fyrox type, however it has implementation of Visit and
// can be serialized in one call.
self.machine.visit("Machine", visitor)?;
self.machine.visit("Machine", &mut region)?;
// This line should always be in pair with enter_region. It pops current node from
// internal stack of visitor and makes parent node current.
visitor.leave_region()
Ok(())
}
}
// Continue implementing Visit trait for Rest of game structures.
impl Visit for Player {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.model.visit("Model", visitor)?;
self.body.visit("Body", visitor)?;
self.camera_pivot.visit("CameraPivot", visitor)?;
self.camera_hinge.visit("CameraHinge", visitor)?;
self.camera.visit("Camera", visitor)?;
self.model.visit("Model", &mut region)?;
self.body.visit("Body", &mut region)?;
self.camera_pivot.visit("CameraPivot", &mut region)?;
self.camera_hinge.visit("CameraHinge", &mut region)?;
self.camera.visit("Camera", &mut region)?;
self.locomotion_machine
.visit("LocomotionMachine", visitor)?;
self.model_yaw.visit("ModelYaw", visitor)?;
self.pivot.visit("Pivot", visitor)?;
.visit("LocomotionMachine", &mut region)?;
self.model_yaw.visit("ModelYaw", &mut region)?;
self.pivot.visit("Pivot", &mut region)?;
// self.input_controller isn't visited because we don't care about its state -
// it will be synced with keyboard state anyway.
visitor.leave_region()
Ok(())
}
}
impl Visit for GameScene {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.scene.visit("Scene", visitor)?;
self.player.visit("Player", visitor)?;
self.scene.visit("Scene", &mut region)?;
self.player.visit("Player", &mut region)?;
visitor.leave_region()
Ok(())
}
}
+6 -6
View File
@@ -28,9 +28,9 @@ fn impl_visit_struct(
utils::create_field_visits(None, field_args.fields.iter(), field_args.style);
quote! {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
#(self.#field_visits)*
visitor.leave_region()
Ok(())
}
};
@@ -187,12 +187,12 @@ fn impl_visit_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs])
ty_args,
variant_args.iter().flat_map(|v| v.fields.iter()).cloned(),
quote! {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut id = id(self);
id.visit("Id", visitor)?;
id.visit("Id", &mut region)?;
if visitor.is_reading() {
if region.is_reading() {
*self = from_id(id)?;
}
@@ -200,7 +200,7 @@ fn impl_visit_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs])
#(#variant_visits)*
}
return visitor.leave_region();
return Ok(());
#fn_id
+2 -2
View File
@@ -119,11 +119,11 @@ pub fn create_field_visits<'a>(
.map(|(ident, name, optional)| {
if *optional {
quote! {
#ident.visit(#name, visitor).ok();
#ident.visit(#name, &mut region).ok();
}
} else {
quote! {
#ident.visit(#name, visitor)?;
#ident.visit(#name, &mut region)?;
}
}
})
+1 -14
View File
@@ -4,7 +4,7 @@ use crate::{
};
use std::ops::{Add, AddAssign, Sub, SubAssign};
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Visit)]
#[repr(C)]
pub struct Color {
// Do not change order! OpenGL requires this order!
@@ -301,19 +301,6 @@ impl Color {
}
}
impl Visit for Color {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.r.visit("R", visitor)?;
self.g.visit("G", visitor)?;
self.b.visit("B", visitor)?;
self.a.visit("A", visitor)?;
visitor.leave_region()
}
}
impl Add for Color {
type Output = Self;
+2 -23
View File
@@ -4,23 +4,12 @@ use crate::{
};
use std::cmp::Ordering;
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Visit)]
pub struct GradientPoint {
location: f32,
color: Color,
}
impl Visit for GradientPoint {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.location.visit("Location", visitor)?;
self.color.visit("Color", visitor)?;
visitor.leave_region()
}
}
impl GradientPoint {
pub fn new(location: f32, color: Color) -> Self {
Self { location, color }
@@ -45,7 +34,7 @@ impl Clone for GradientPoint {
}
}
#[derive(PartialEq, Debug)]
#[derive(PartialEq, Debug, Visit)]
pub struct ColorGradient {
points: Vec<GradientPoint>,
}
@@ -58,16 +47,6 @@ impl Clone for ColorGradient {
}
}
impl Visit for ColorGradient {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.points.visit("Points", visitor)?;
visitor.leave_region()
}
}
impl Default for ColorGradient {
fn default() -> Self {
Self::new()
+4 -4
View File
@@ -257,12 +257,12 @@ where
V: Hash + Eq + Clone + Default + Visit,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.forward_map.visit("ForwardMap", visitor)?;
self.backward_map.visit("BackwardMap", visitor)?;
self.forward_map.visit("ForwardMap", &mut region)?;
self.backward_map.visit("BackwardMap", &mut region)?;
visitor.leave_region()
Ok(())
}
}
+1 -12
View File
@@ -4,7 +4,7 @@ use crate::{
visitor::{Visit, VisitResult, Visitor},
};
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Visit)]
pub struct AxisAlignedBoundingBox {
pub min: Vector3<f32>,
pub max: Vector3<f32>,
@@ -257,17 +257,6 @@ impl AxisAlignedBoundingBox {
}
}
impl Visit for AxisAlignedBoundingBox {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.min.visit("Min", visitor)?;
self.max.visit("Max", visitor)?;
visitor.leave_region()
}
}
#[cfg(test)]
mod test {
use crate::algebra::{Matrix4, Vector3};
+8 -8
View File
@@ -252,15 +252,15 @@ impl Frustum {
impl Visit for Frustum {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.planes[0].visit("Left", visitor)?;
self.planes[1].visit("Right", visitor)?;
self.planes[2].visit("Top", visitor)?;
self.planes[3].visit("Bottom", visitor)?;
self.planes[4].visit("Far", visitor)?;
self.planes[5].visit("Near", visitor)?;
self.planes[0].visit("Left", &mut region)?;
self.planes[1].visit("Right", &mut region)?;
self.planes[2].visit("Top", &mut region)?;
self.planes[3].visit("Bottom", &mut region)?;
self.planes[4].visit("Far", &mut region)?;
self.planes[5].visit("Near", &mut region)?;
visitor.leave_region()
Ok(())
}
}
+12 -24
View File
@@ -283,14 +283,14 @@ where
T: NumAssign + Scalar + Visit + PartialOrd + Copy + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.position.x.visit("X", visitor)?;
self.position.y.visit("Y", visitor)?;
self.size.x.visit("W", visitor)?;
self.size.y.visit("H", visitor)?;
self.position.x.visit("X", &mut region)?;
self.position.y.visit("Y", &mut region)?;
self.size.x.visit("W", &mut region)?;
self.size.y.visit("H", &mut region)?;
visitor.leave_region()
Ok(())
}
}
@@ -732,13 +732,13 @@ impl TriangleDefinition {
impl Visit for TriangleDefinition {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.0[0].visit("A", visitor)?;
self.0[1].visit("B", visitor)?;
self.0[2].visit("C", visitor)?;
self.0[0].visit("A", &mut region)?;
self.0[1].visit("B", &mut region)?;
self.0[2].visit("C", &mut region)?;
visitor.leave_region()
Ok(())
}
}
@@ -846,7 +846,7 @@ pub fn get_closest_point_triangle_set<P: PositionProvider>(
closest_index
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Visit)]
pub struct SmoothAngle {
/// Current angle in radians.
pub angle: f32,
@@ -941,18 +941,6 @@ impl Default for SmoothAngle {
}
}
impl Visit for SmoothAngle {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.angle.visit("Angle", visitor)?;
self.target.visit("Target", visitor)?;
self.speed.visit("Speed", visitor)?;
visitor.leave_region()
}
}
#[derive(Copy, Clone, Hash, PartialOrd, PartialEq, Ord, Eq)]
pub enum RotationOrder {
XYZ,
+1 -12
View File
@@ -1,7 +1,7 @@
use crate::algebra::Vector3;
use crate::visitor::{Visit, VisitResult, Visitor};
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Visit)]
pub struct Plane {
pub normal: Vector3<f32>,
pub d: f32,
@@ -69,17 +69,6 @@ impl Plane {
}
}
impl Visit for Plane {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.normal.visit("Normal", visitor)?;
self.d.visit("D", visitor)?;
visitor.leave_region()
}
}
#[test]
fn plane_sanity_tests() {
// Computation test
+13 -24
View File
@@ -164,7 +164,7 @@ impl<T> Display for Handle<T> {
}
/// Type-erased handle.
#[derive(Copy, Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Hash, Inspect)]
#[derive(Copy, Clone, Debug, Ord, PartialOrd, PartialEq, Eq, Hash, Inspect, Visit)]
pub struct ErasedHandle {
/// Index of object in pool.
#[inspect(read_only)]
@@ -200,17 +200,6 @@ impl<T> From<Handle<T>> for ErasedHandle {
}
}
impl Visit for ErasedHandle {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.index.visit("Index", visitor)?;
self.generation.visit("Generation", visitor)?;
visitor.leave_region()
}
}
impl ErasedHandle {
pub fn none() -> Self {
Self {
@@ -246,12 +235,12 @@ impl ErasedHandle {
impl<T> Visit for Handle<T> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.index.visit("Index", visitor)?;
self.generation.visit("Generation", visitor)?;
self.index.visit("Index", &mut region)?;
self.generation.visit("Generation", &mut region)?;
visitor.leave_region()
Ok(())
}
}
@@ -305,12 +294,12 @@ where
P: PayloadContainer<Element = T> + Visit,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.generation.visit("Generation", visitor)?;
self.payload.visit("Payload", visitor)?;
self.generation.visit("Generation", &mut region)?;
self.payload.visit("Payload", &mut region)?;
visitor.leave_region()
Ok(())
}
}
@@ -340,10 +329,10 @@ where
P: PayloadContainer<Element = T> + Default + Visit + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.records.visit("Records", visitor)?;
self.free_stack.visit("FreeStack", visitor)?;
visitor.leave_region()
let mut region = visitor.enter_region(name)?;
self.records.visit("Records", &mut region)?;
self.free_stack.visit("FreeStack", &mut region)?;
Ok(())
}
}
+145 -177
View File
@@ -28,6 +28,7 @@ use crate::{
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fxhash::FxHashMap;
use std::collections::HashMap;
use std::ops::Deref;
use std::time::Duration;
use std::{
any::Any,
@@ -709,6 +710,31 @@ impl Default for Node {
}
}
#[must_use = "the guard must be used"]
pub struct RegionGuard<'a>(&'a mut Visitor);
impl<'a> Deref for RegionGuard<'a> {
type Target = Visitor;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a> DerefMut for RegionGuard<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<'a> Drop for RegionGuard<'a> {
fn drop(&mut self) {
// If we acquired RegionGuard instance, then it is safe to assert that
// `leave_region` was successful.
self.0.leave_region().unwrap();
}
}
pub struct Visitor {
nodes: Pool<Node>,
rc_map: FxHashMap<u64, Rc<dyn Any>>,
@@ -764,7 +790,7 @@ impl Visitor {
self.nodes.borrow_mut(self.current_node)
}
pub fn enter_region(&mut self, name: &str) -> VisitResult {
pub fn enter_region(&mut self, name: &str) -> Result<RegionGuard, VisitError> {
let node = self.nodes.borrow(self.current_node);
if self.reading {
let mut region = Handle::NONE;
@@ -777,7 +803,7 @@ impl Visitor {
}
if region.is_some() {
self.current_node = region;
Ok(())
Ok(RegionGuard(self))
} else {
Err(VisitError::RegionDoesNotExist(name.to_owned()))
}
@@ -797,7 +823,7 @@ impl Visitor {
.push(node_handle);
self.current_node = node_handle;
Ok(())
Ok(RegionGuard(self))
}
}
@@ -807,7 +833,7 @@ impl Visitor {
.map(|n| n.name.as_str())
}
pub fn leave_region(&mut self) -> VisitResult {
fn leave_region(&mut self) -> VisitResult {
self.current_node = self.nodes.borrow(self.current_node).parent;
if self.current_node.is_none() {
Err(VisitError::NoActiveNode)
@@ -952,29 +978,27 @@ where
T: Default + Visit + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut len = self.len() as u32;
len.visit("Length", visitor)?;
len.visit("Length", &mut region)?;
if visitor.reading {
if region.reading {
for index in 0..len {
let region_name = format!("Item{}", index);
visitor.enter_region(region_name.as_str())?;
let mut region = region.enter_region(region_name.as_str())?;
let mut object = T::default();
object.visit("ItemData", visitor)?;
object.visit("ItemData", &mut region)?;
self.push(object);
visitor.leave_region()?;
}
} else {
for (index, item) in self.iter_mut().enumerate() {
let region_name = format!("Item{}", index);
visitor.enter_region(region_name.as_str())?;
item.visit("ItemData", visitor)?;
visitor.leave_region()?;
let mut region = region.enter_region(region_name.as_str())?;
item.visit("ItemData", &mut region)?;
}
}
visitor.leave_region()?;
Ok(())
}
}
@@ -984,52 +1008,51 @@ where
T: Default + Visit + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut is_some = if self.is_some() { 1u8 } else { 0u8 };
is_some.visit("IsSome", visitor)?;
is_some.visit("IsSome", &mut region)?;
if is_some != 0 {
if visitor.reading {
if region.reading {
let mut value = T::default();
value.visit("Data", visitor)?;
value.visit("Data", &mut region)?;
*self = Some(value);
} else {
self.as_mut().unwrap().visit("Data", visitor)?;
self.as_mut().unwrap().visit("Data", &mut region)?;
}
}
visitor.leave_region()?;
Ok(())
}
}
impl Visit for String {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut len = self.as_bytes().len() as u32;
len.visit("Length", visitor)?;
len.visit("Length", &mut region)?;
let mut data = if visitor.reading {
let mut data = if region.reading {
Vec::new()
} else {
Vec::from(self.as_bytes())
};
let mut proxy = Data { vec: &mut data };
proxy.visit("Data", visitor)?;
proxy.visit("Data", &mut region)?;
if visitor.reading {
if region.reading {
*self = String::from_utf8(data)?;
}
visitor.leave_region()
Ok(())
}
}
impl Visit for PathBuf {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
// We have to replace Windows back slashes \ to forward / to make paths portable
// across all OSes.
@@ -1042,22 +1065,22 @@ impl Visit for PathBuf {
};
let mut len = bytes.len() as u32;
len.visit("Length", visitor)?;
len.visit("Length", &mut region)?;
let mut data = if visitor.reading {
let mut data = if region.reading {
Vec::new()
} else {
Vec::from(bytes)
};
let mut proxy = Data { vec: &mut data };
proxy.visit("Data", visitor)?;
proxy.visit("Data", &mut region)?;
if visitor.reading {
if region.reading {
*self = PathBuf::from(String::from_utf8(data)?);
}
visitor.leave_region()
Ok(())
}
}
@@ -1080,15 +1103,15 @@ where
T: Visit + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
if visitor.reading {
if region.reading {
let mut raw = 0u64;
raw.visit("Id", visitor)?;
raw.visit("Id", &mut region)?;
if raw == 0 {
return Err(VisitError::UnexpectedRcNullIndex);
}
if let Some(ptr) = visitor.rc_map.get(&raw) {
if let Some(ptr) = region.rc_map.get(&raw) {
if let Ok(res) = Rc::downcast::<T>(ptr.clone()) {
*self = res;
} else {
@@ -1096,10 +1119,10 @@ where
}
} else {
// Remember that we already visited data Rc store.
visitor.rc_map.insert(raw as u64, self.clone());
region.rc_map.insert(raw as u64, self.clone());
let raw = rc_to_raw(self);
unsafe { &mut *raw }.visit("RcData", visitor)?;
unsafe { &mut *raw }.visit("RcData", &mut region)?;
}
} else {
// Take raw pointer to inner data.
@@ -1107,16 +1130,14 @@ where
// Save it as id.
let mut index = raw as u64;
index.visit("Id", visitor)?;
index.visit("Id", &mut region)?;
if let Entry::Vacant(entry) = visitor.rc_map.entry(index) {
if let Entry::Vacant(entry) = region.rc_map.entry(index) {
entry.insert(self.clone());
unsafe { &mut *raw }.visit("RcData", visitor)?;
unsafe { &mut *raw }.visit("RcData", &mut region)?;
}
}
visitor.leave_region()?;
Ok(())
}
}
@@ -1170,15 +1191,15 @@ where
T: Visit + Send + Sync + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
if visitor.reading {
if region.reading {
let mut raw = 0u64;
raw.visit("Id", visitor)?;
raw.visit("Id", &mut region)?;
if raw == 0 {
return Err(VisitError::UnexpectedRcNullIndex);
}
if let Some(ptr) = visitor.arc_map.get(&raw) {
if let Some(ptr) = &mut region.arc_map.get(&raw) {
if let Ok(res) = Arc::downcast::<T>(ptr.clone()) {
*self = res;
} else {
@@ -1186,10 +1207,10 @@ where
}
} else {
// Remember that we already visited data Rc store.
visitor.arc_map.insert(raw as u64, self.clone());
region.arc_map.insert(raw as u64, self.clone());
let raw = arc_to_raw(self);
unsafe { &mut *raw }.visit("ArcData", visitor)?;
unsafe { &mut *raw }.visit("ArcData", &mut region)?;
}
} else {
// Take raw pointer to inner data.
@@ -1197,16 +1218,14 @@ where
// Save it as id.
let mut index = raw as u64;
index.visit("Id", visitor)?;
index.visit("Id", &mut region)?;
if let Entry::Vacant(entry) = visitor.arc_map.entry(index) {
if let Entry::Vacant(entry) = region.arc_map.entry(index) {
entry.insert(self.clone());
unsafe { &mut *raw }.visit("ArcData", visitor)?;
unsafe { &mut *raw }.visit("ArcData", &mut region)?;
}
}
visitor.leave_region()?;
Ok(())
}
}
@@ -1216,14 +1235,14 @@ where
T: Default + Visit + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
if visitor.reading {
if region.reading {
let mut raw = 0u64;
raw.visit("Id", visitor)?;
raw.visit("Id", &mut region)?;
if raw != 0 {
if let Some(ptr) = visitor.rc_map.get(&raw) {
if let Some(ptr) = &mut region.rc_map.get(&raw) {
if let Ok(res) = Rc::downcast::<T>(ptr.clone()) {
*self = Rc::downgrade(&res);
} else {
@@ -1232,10 +1251,10 @@ where
} else {
// Create new value wrapped into Rc and deserialize it.
let rc = Rc::new(T::default());
visitor.rc_map.insert(raw as u64, rc.clone());
region.rc_map.insert(raw as u64, rc.clone());
let raw = rc_to_raw(&rc);
unsafe { &mut *raw }.visit("RcData", visitor)?;
unsafe { &mut *raw }.visit("RcData", &mut region)?;
*self = Rc::downgrade(&rc);
}
@@ -1246,19 +1265,17 @@ where
// Save it as id.
let mut index = raw as u64;
index.visit("Id", visitor)?;
index.visit("Id", &mut region)?;
if let Entry::Vacant(entry) = visitor.rc_map.entry(index) {
if let Entry::Vacant(entry) = region.rc_map.entry(index) {
entry.insert(rc);
unsafe { &mut *raw }.visit("RcData", visitor)?;
unsafe { &mut *raw }.visit("RcData", &mut region)?;
}
} else {
let mut index = 0u64;
index.visit("Id", visitor)?;
index.visit("Id", &mut region)?;
}
visitor.leave_region()?;
Ok(())
}
}
@@ -1268,14 +1285,14 @@ where
T: Default + Visit + Send + Sync + 'static,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
if visitor.reading {
if region.reading {
let mut raw = 0u64;
raw.visit("Id", visitor)?;
raw.visit("Id", &mut region)?;
if raw != 0 {
if let Some(ptr) = visitor.arc_map.get(&raw) {
if let Some(ptr) = region.arc_map.get(&raw) {
if let Ok(res) = Arc::downcast::<T>(ptr.clone()) {
*self = Arc::downgrade(&res);
} else {
@@ -1284,10 +1301,10 @@ where
} else {
// Create new value wrapped into Arc and deserialize it.
let arc = Arc::new(T::default());
visitor.arc_map.insert(raw as u64, arc.clone());
region.arc_map.insert(raw as u64, arc.clone());
let raw = arc_to_raw(&arc);
unsafe { &mut *raw }.visit("ArcData", visitor)?;
unsafe { &mut *raw }.visit("ArcData", &mut region)?;
*self = Arc::downgrade(&arc);
}
@@ -1298,19 +1315,17 @@ where
// Save it as id.
let mut index = raw as u64;
index.visit("Id", visitor)?;
index.visit("Id", &mut region)?;
if let Entry::Vacant(entry) = visitor.arc_map.entry(index) {
if let Entry::Vacant(entry) = region.arc_map.entry(index) {
entry.insert(arc);
unsafe { &mut *raw }.visit("ArcData", visitor)?;
unsafe { &mut *raw }.visit("ArcData", &mut region)?;
}
} else {
let mut index = 0u64;
index.visit("Id", visitor)?;
index.visit("Id", &mut region)?;
}
visitor.leave_region()?;
Ok(())
}
}
@@ -1321,43 +1336,39 @@ where
V: Visit + Default,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut count = self.len() as u32;
count.visit("Count", visitor)?;
count.visit("Count", &mut region)?;
if visitor.is_reading() {
if region.is_reading() {
for i in 0..(count as usize) {
let name = format!("Item{}", i);
visitor.enter_region(name.as_str())?;
let mut region = region.enter_region(name.as_str())?;
let mut key = K::default();
key.visit("Key", visitor)?;
key.visit("Key", &mut region)?;
let mut value = V::default();
value.visit("Value", visitor)?;
value.visit("Value", &mut region)?;
self.insert(key, value);
visitor.leave_region()?;
}
} else {
for (i, (key, value)) in self.iter_mut().enumerate() {
let name = format!("Item{}", i);
visitor.enter_region(name.as_str())?;
let mut region = region.enter_region(name.as_str())?;
let mut key = key.clone();
key.visit("Key", visitor)?;
key.visit("Key", &mut region)?;
value.visit("Value", visitor)?;
visitor.leave_region()?;
value.visit("Value", &mut region)?;
}
}
visitor.leave_region()
Ok(())
}
}
@@ -1367,54 +1378,50 @@ where
V: Visit + Default,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut count = self.len() as u32;
count.visit("Count", visitor)?;
count.visit("Count", &mut region)?;
if visitor.is_reading() {
if region.is_reading() {
for i in 0..(count as usize) {
let name = format!("Item{}", i);
visitor.enter_region(name.as_str())?;
let mut region = region.enter_region(name.as_str())?;
let mut key = K::default();
key.visit("Key", visitor)?;
key.visit("Key", &mut region)?;
let mut value = V::default();
value.visit("Value", visitor)?;
value.visit("Value", &mut region)?;
self.insert(key, value);
visitor.leave_region()?;
}
} else {
for (i, (key, value)) in self.iter_mut().enumerate() {
let name = format!("Item{}", i);
visitor.enter_region(name.as_str())?;
let mut region = region.enter_region(name.as_str())?;
let mut key = key.clone();
key.visit("Key", visitor)?;
key.visit("Key", &mut region)?;
value.visit("Value", visitor)?;
visitor.leave_region()?;
value.visit("Value", &mut region)?;
}
}
visitor.leave_region()
Ok(())
}
}
impl<T: Default + Visit, const SIZE: usize> Visit for [T; SIZE] {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut len = SIZE as u32;
len.visit("Length", visitor)?;
len.visit("Length", &mut region)?;
if visitor.reading {
if region.reading {
if len > SIZE as u32 {
return VisitResult::Err(VisitError::User(format!(
"Not enough space in static array, got {}, needed {}!",
@@ -1424,103 +1431,93 @@ impl<T: Default + Visit, const SIZE: usize> Visit for [T; SIZE] {
for index in 0..len {
let region_name = format!("Item{}", index);
visitor.enter_region(region_name.as_str())?;
let mut region = region.enter_region(region_name.as_str())?;
let mut object = T::default();
object.visit("ItemData", visitor)?;
object.visit("ItemData", &mut region)?;
self[index as usize] = object;
visitor.leave_region()?;
}
} else {
for (index, item) in self.iter_mut().enumerate() {
let region_name = format!("Item{}", index);
visitor.enter_region(region_name.as_str())?;
item.visit("ItemData", visitor)?;
visitor.leave_region()?;
let mut region = region.enter_region(region_name.as_str())?;
item.visit("ItemData", &mut region)?;
}
}
visitor.leave_region()
Ok(())
}
}
impl Visit for Duration {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut secs: u64 = self.as_secs();
let mut nanos: u32 = self.subsec_nanos();
secs.visit("Secs", visitor)?;
nanos.visit("Nanos", visitor)?;
secs.visit("Secs", &mut region)?;
nanos.visit("Nanos", &mut region)?;
if visitor.is_reading() {
if region.is_reading() {
*self = Duration::new(secs, nanos);
}
visitor.leave_region()
Ok(())
}
}
impl<T: Visit> Visit for Range<T> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.start.visit("Start", visitor)?;
self.end.visit("End", visitor)?;
self.start.visit("Start", &mut region)?;
self.end.visit("End", &mut region)?;
visitor.leave_region()
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::visitor::{Data, Visit, VisitError, VisitResult, Visitor};
use crate::visitor::{Data, Visit, VisitResult, Visitor};
use std::{fs::File, io::Write, path::Path, rc::Rc};
#[derive(Visit, Default)]
pub struct Model {
data: u64,
}
#[derive(Default)]
pub struct Texture {
data: Vec<u8>,
}
impl Visit for Texture {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut proxy = Data {
vec: &mut self.data,
};
proxy.visit("Data", visitor)?;
visitor.leave_region()
}
}
impl Visit for Model {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.data.visit("Data", visitor)?;
visitor.leave_region()
}
}
impl Visit for ResourceKind {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
match self {
ResourceKind::Unknown => Err(VisitError::User("invalid resource type".to_string())),
ResourceKind::Texture(tex) => tex.visit(name, visitor),
ResourceKind::Model(model) => model.visit(name, visitor),
}
proxy.visit("Data", &mut region)?;
Ok(())
}
}
#[allow(dead_code)]
#[derive(Visit)]
pub enum ResourceKind {
Unknown,
Model(Model),
Texture(Texture),
}
impl Default for ResourceKind {
fn default() -> Self {
Self::Unknown
}
}
#[derive(Visit)]
struct Resource {
kind: ResourceKind,
data: u16,
@@ -1541,27 +1538,7 @@ mod test {
}
}
impl Visit for Resource {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
if visitor.reading {
} else {
let mut kind_id: u8 = match &self.kind {
ResourceKind::Unknown => {
return Err(VisitError::User("Invalid resource!".to_string()))
}
ResourceKind::Model(_) => 0,
ResourceKind::Texture(_) => 1,
};
kind_id.visit("KindId", visitor)?;
self.kind.visit("KindData", visitor)?;
}
self.data.visit("ResData", visitor)?;
visitor.leave_region()
}
}
#[derive(Default)]
#[derive(Default, Visit)]
struct Foo {
bar: u64,
shared_resource: Option<Rc<Resource>>,
@@ -1576,15 +1553,6 @@ mod test {
}
}
impl Visit for Foo {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.bar.visit("Bar", visitor)?;
self.shared_resource.visit("SharedResource", visitor)?;
visitor.leave_region()
}
}
#[test]
fn visitor_test() {
let path = Path::new("test.bin");
+6 -6
View File
@@ -76,11 +76,11 @@ where
E: ResourceLoadError,
{
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut id = self.id();
id.visit("Id", visitor)?;
if visitor.is_reading() {
id.visit("Id", &mut region)?;
if region.is_reading() {
*self = Self::from_id(id)?;
}
@@ -91,11 +91,11 @@ where
),
// This may look strange if we attempting to save an invalid resource, but this may be
// actually useful - a resource may become loadable at the deserialization.
Self::LoadError { path, .. } => path.visit("Path", visitor)?,
Self::Ok(details) => details.visit("Details", visitor)?,
Self::LoadError { path, .. } => path.visit("Path", &mut region)?,
Self::Ok(details) => details.visit("Details", &mut region)?,
}
visitor.leave_region()
Ok(())
}
}
+5 -11
View File
@@ -28,27 +28,21 @@ use std::path::Path;
use std::{path::PathBuf, time::Duration};
/// Generic sound buffer that contains decoded samples and allows random access.
#[derive(Debug, Default)]
#[derive(Debug, Default, Visit)]
pub struct GenericBuffer {
/// Interleaved decoded samples (mono sounds: L..., stereo sounds: LR...)
/// For streaming buffers it contains only small part of decoded data
/// (usually something around 1 sec).
#[visit(skip)]
pub(in crate) samples: Vec<f32>,
#[visit(skip)]
pub(in crate) channel_count: usize,
#[visit(skip)]
pub(in crate) sample_rate: usize,
#[visit(rename = "Path")]
pub(in crate) external_source_path: PathBuf,
}
impl Visit for GenericBuffer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.external_source_path.visit("Path", visitor)?;
visitor.leave_region()
}
}
impl GenericBuffer {
/// Creates new generic buffer from specified data source. May fail if data source has unsupported
/// format, corrupted, etc.
+3 -11
View File
@@ -37,13 +37,15 @@ use std::ops::{Deref, DerefMut};
use std::time::Duration;
/// Streaming buffer for long sounds. Does not support random access.
#[derive(Debug, Default)]
#[derive(Debug, Default, Visit)]
pub struct StreamingBuffer {
pub(in crate) generic: GenericBuffer,
/// Count of sources that share this buffer, it is important to keep only one
/// user of streaming buffer, because streaming buffer does not allow random
/// access.
#[visit(skip)]
pub(in crate) use_count: usize,
#[visit(skip)]
streaming_source: StreamingSource,
}
@@ -221,13 +223,3 @@ impl DerefMut for StreamingBuffer {
&mut self.generic
}
}
impl Visit for StreamingBuffer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.generic.visit("Generic", visitor)?;
visitor.leave_region()
}
}
+10 -36
View File
@@ -86,7 +86,7 @@ impl Default for DistanceModel {
}
/// See module docs.
#[derive(Clone, Default, Debug)]
#[derive(Clone, Default, Debug, Visit)]
pub struct SoundContext {
pub(in crate) state: Option<Arc<Mutex<State>>>,
}
@@ -372,50 +372,24 @@ impl SoundContext {
}
}
impl Visit for SoundContext {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.state.visit("State", visitor)?;
visitor.leave_region()
}
}
impl Visit for State {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
if visitor.is_reading() {
self.sources.clear();
self.effects.clear();
self.renderer = Renderer::Default;
}
self.master_gain.visit("MasterGain", visitor)?;
self.listener.visit("Listener", visitor)?;
self.sources.visit("Sources", visitor)?;
self.effects.visit("Effects", visitor)?;
self.renderer.visit("Renderer", visitor)?;
let _ = self.paused.visit("Paused", visitor);
let mut region = visitor.enter_region(name)?;
let mut distance_model = self.distance_model as u32;
distance_model.visit("DistanceModel", visitor)?;
if visitor.is_reading() {
self.distance_model = match distance_model {
0 => DistanceModel::None,
1 => DistanceModel::InverseDistance,
2 => DistanceModel::LinearDistance,
3 => DistanceModel::ExponentDistance,
_ => {
return VisitResult::Err(VisitError::User(format!(
"Invalid distance model id {}!",
distance_model
)))
}
}
}
self.master_gain.visit("MasterGain", &mut region)?;
self.listener.visit("Listener", &mut region)?;
self.sources.visit("Sources", &mut region)?;
self.effects.visit("Effects", &mut region)?;
self.renderer.visit("Renderer", &mut region)?;
self.paused.visit("Paused", &mut region)?;
self.distance_model.visit("DistanceModel", &mut region)?;
visitor.leave_region()
Ok(())
}
}
+4 -55
View File
@@ -14,7 +14,7 @@ use fyrox_core::{
/// One-pole Filter.
/// For details see - <https://www.earlevel.com/main/2012/12/15/a-one-pole-filter/>
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct OnePole {
a0: f32,
b1: f32,
@@ -66,21 +66,9 @@ impl OnePole {
}
}
impl Visit for OnePole {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.a0.visit("A0", visitor)?;
self.b1.visit("B1", visitor)?;
self.last.visit("Last", visitor)?;
visitor.leave_region()
}
}
/// Lowpass-Feedback Comb Filter
/// For details see - <https://ccrma.stanford.edu/~jos/pasp/Lowpass_Feedback_Comb_Filter.html>
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct LpfComb {
low_pass: OnePole,
delay_line: DelayLine,
@@ -135,21 +123,9 @@ impl LpfComb {
}
}
impl Visit for LpfComb {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.delay_line.visit("DelayLine", visitor)?;
self.feedback.visit("Feedback", visitor)?;
self.low_pass.visit("LowPass", visitor)?;
visitor.leave_region()
}
}
/// Allpass Filter - <https://ccrma.stanford.edu/~jos/pasp/Allpass_Filters.html>
/// For details see - <https://ccrma.stanford.edu/~jos/pasp/Allpass_Two_Combs.html>
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct AllPass {
delay_line: DelayLine,
gain: f32,
@@ -194,17 +170,6 @@ impl AllPass {
}
}
impl Visit for AllPass {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.delay_line.visit("DelayLine", visitor)?;
self.gain.visit("Gain", visitor)?;
visitor.leave_region()
}
}
/// Exact kind of biquad filter - it defines coefficients of the filter.
/// More info here: <https://shepazu.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html>
pub enum BiquadKind {
@@ -231,7 +196,7 @@ pub enum BiquadKind {
/// Generic second order digital filter.
/// More info here: <https://ccrma.stanford.edu/~jos/filters/BiQuad_Section.html>
#[derive(Clone, Debug, Inspect)]
#[derive(Clone, Debug, Inspect, Visit)]
pub struct Biquad {
/// B0 Coefficient of the equation.
pub b0: f32,
@@ -376,19 +341,3 @@ impl Default for Biquad {
}
}
}
impl Visit for Biquad {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.b0.visit("b0", visitor)?;
self.b1.visit("b1", visitor)?;
self.b2.visit("b2", visitor)?;
self.a1.visit("a1", visitor)?;
self.a2.visit("a2", visitor)?;
self.prev1.visit("prev1", visitor)?;
self.prev2.visit("prev2", visitor)?;
visitor.leave_region()
}
}
+1 -13
View File
@@ -13,7 +13,7 @@ use fyrox_core::visitor::{Visit, VisitResult, Visitor};
pub mod filters;
/// See more info here <https://ccrma.stanford.edu/~jos/pasp/Delay_Lines.html>
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct DelayLine {
samples: Vec<f32>,
last: f32,
@@ -62,18 +62,6 @@ impl Default for DelayLine {
}
}
impl Visit for DelayLine {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.last.visit("Last", visitor)?;
self.pos.visit("Pos", visitor)?;
self.samples.visit("Samples", visitor)?;
visitor.leave_region()
}
}
/// Calculates single coefficient of Hamming window.
/// <https://en.wikipedia.org/wiki/Window_function#Hamming_window>
pub fn hamming_window(i: usize, sample_count: usize) -> f32 {
+7 -84
View File
@@ -21,21 +21,11 @@ use std::ops::{Deref, DerefMut};
pub mod reverb;
/// Stub effect that does nothing.
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Visit)]
pub struct StubEffect {
base: BaseEffect,
}
impl Visit for StubEffect {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.base.visit("Base", visitor)?;
visitor.leave_region()
}
}
impl EffectRenderTrait for StubEffect {
fn render(
&mut self,
@@ -62,7 +52,7 @@ impl DerefMut for StubEffect {
}
/// See module docs.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub enum Effect {
/// Stub effect that does nothing.
Stub(StubEffect),
@@ -76,42 +66,6 @@ impl Default for Effect {
}
}
impl Effect {
fn id(&self) -> u32 {
match self {
Effect::Stub(_) => 0,
Effect::Reverb(_) => 1,
}
}
fn from_id(id: u32) -> Result<Self, String> {
match id {
0 => Ok(Effect::Stub(Default::default())),
1 => Ok(Effect::Reverb(Default::default())),
_ => Err(format!("Unknown effect id {}", id)),
}
}
}
impl Visit for Effect {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut id = self.id();
id.visit("Id", visitor)?;
if visitor.is_reading() {
*self = Self::from_id(id)?;
}
match self {
Effect::Stub(v) => v.visit("Data", visitor)?,
Effect::Reverb(v) => v.visit("Data", visitor)?,
}
visitor.leave_region()
}
}
pub(in crate) trait EffectRenderTrait {
fn render(
&mut self,
@@ -124,10 +78,11 @@ pub(in crate) trait EffectRenderTrait {
/// Base effect for all other kinds of effects. It contains set of inputs (direct
/// or filtered), provides some basic methods to control them.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct BaseEffect {
gain: f32,
inputs: Vec<EffectInput>,
#[visit(skip)]
frame_samples: Vec<(f32, f32)>,
}
@@ -231,20 +186,9 @@ impl BaseEffect {
}
}
impl Visit for BaseEffect {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.gain.visit("Gain", visitor)?;
self.inputs.visit("Inputs", visitor)?;
visitor.leave_region()
}
}
/// Input filter is used to transform samples in desired manner, it is based
/// on generic second order biquad filter. See docs for Biquad filter.
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Visit)]
pub struct InputFilter {
left: Biquad,
right: Biquad,
@@ -266,21 +210,10 @@ impl InputFilter {
}
}
impl Visit for InputFilter {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.left.visit("Left", visitor)?;
self.right.visit("Right", visitor)?;
visitor.leave_region()
}
}
/// Input is a "reference" to a sound source. Samples of sound source will be
/// either passed directly to effect or will be transformed by filter if one
/// is set.
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Visit)]
pub struct EffectInput {
/// Handle of source from which effect will take samples each render frame.
source: Handle<SoundSource>,
@@ -291,6 +224,7 @@ pub struct EffectInput {
/// Distance gain from last frame, it is used to interpolate distance gain from
/// frame to frame to prevent clicks in output signal.
#[visit(skip)]
last_distance_gain: Option<f32>,
}
@@ -319,17 +253,6 @@ impl EffectInput {
}
}
impl Visit for EffectInput {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.source.visit("Source", visitor)?;
self.filter.visit("Filter", visitor)?;
visitor.leave_region()
}
}
macro_rules! static_dispatch {
($self:ident, $func:ident, $($args:expr),*) => {
match $self {
+5 -30
View File
@@ -41,12 +41,15 @@ use std::{
time::Duration,
};
#[derive(Default, Debug, Clone)]
#[derive(Default, Debug, Clone, Visit)]
struct ChannelReverb {
#[visit(rename = "FC")]
fc: f32,
sample_rate: u32,
stereo_spread: u32,
#[visit(rename = "LPCFilters")]
lp_fb_comb_filters: Vec<LpfComb>,
#[visit(rename = "APFilters")]
all_pass_filters: Vec<AllPass>,
}
@@ -136,22 +139,8 @@ impl ChannelReverb {
}
}
impl Visit for ChannelReverb {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.all_pass_filters.visit("APFilters", visitor)?;
self.fc.visit("FC", visitor)?;
self.lp_fb_comb_filters.visit("LPCFilters", visitor)?;
self.sample_rate.visit("SampleRate", visitor)?;
self.stereo_spread.visit("StereoSpread", visitor)?;
visitor.leave_region()
}
}
/// See module docs.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct Reverb {
base: BaseEffect,
dry: f32,
@@ -248,20 +237,6 @@ impl Reverb {
}
}
impl Visit for Reverb {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.base.visit("Base", visitor)?;
self.right.visit("Right", visitor)?;
self.left.visit("Left", visitor)?;
self.dry.visit("Dry", visitor)?;
self.wet.visit("Wet", visitor)?;
visitor.leave_region()
}
}
impl EffectRenderTrait for Reverb {
fn render(
&mut self,
+5 -5
View File
@@ -117,15 +117,15 @@ impl SoundEngine {
impl Visit for SoundEngine {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
if visitor.is_reading() {
self.contexts.clear();
}
self.master_gain.visit("MasterGain", visitor)?;
self.contexts.visit("Contexts", visitor)?;
let mut region = visitor.enter_region(name)?;
visitor.leave_region()
self.master_gain.visit("MasterGain", &mut region)?;
self.contexts.visit("Contexts", &mut region)?;
Ok(())
}
}
+1 -12
View File
@@ -10,7 +10,7 @@ use fyrox_core::math::Matrix3Ext;
use fyrox_core::visitor::{Visit, VisitResult, Visitor};
/// See module docs.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Visit)]
pub struct Listener {
basis: Matrix3<f32>,
position: Vector3<f32>,
@@ -98,14 +98,3 @@ impl Listener {
self.basis.side()
}
}
impl Visit for Listener {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.basis.visit("Basis", visitor)?;
self.position.visit("Position", visitor)?;
visitor.leave_region()
}
}
+6 -3
View File
@@ -74,9 +74,12 @@ pub struct HrtfRenderer {
impl Visit for HrtfRenderer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.hrir_path.visit("ResourcePath", &mut region)?;
drop(region);
self.hrir_path.visit("ResourcePath", visitor)?;
if visitor.is_reading() {
self.processor = Some(hrtf::HrtfProcessor::new(
HrirSphere::from_file(&self.hrir_path, context::SAMPLE_RATE).unwrap(),
@@ -85,7 +88,7 @@ impl Visit for HrtfRenderer {
));
}
visitor.leave_region()
Ok(())
}
}
+1 -38
View File
@@ -24,7 +24,7 @@ pub mod hrtf;
// This "large size difference" is not a problem because renderer
// can be only one at a time on context.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, AsRefStr, EnumString, EnumVariantNames)]
#[derive(Debug, Clone, AsRefStr, EnumString, EnumVariantNames, Visit)]
pub enum Renderer {
/// Stateless default renderer.
Default,
@@ -45,23 +45,6 @@ impl Inspect for Renderer {
}
}
impl Renderer {
fn id(&self) -> u32 {
match self {
Renderer::Default => 0,
Renderer::HrtfRenderer(_) => 1,
}
}
fn from_id(id: u32) -> Result<Self, String> {
match id {
0 => Ok(Self::Default),
1 => Ok(Self::HrtfRenderer(HrtfRenderer::default())),
_ => Err(format!("Invalid renderer id {}!", id)),
}
}
}
impl Default for Renderer {
fn default() -> Self {
Self::Default
@@ -133,23 +116,3 @@ pub(in crate) fn render_source_2d_only(source: &mut SoundSource, mix_buffer: &mu
source.last_left_gain = Some(left_gain);
source.last_right_gain = Some(right_gain);
}
impl Visit for Renderer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut id = self.id();
id.visit("Id", visitor)?;
if visitor.is_reading() {
*self = Self::from_id(id)?;
}
match self {
Renderer::Default => {}
Renderer::HrtfRenderer(hrtf) => {
hrtf.visit("Hrtf", visitor)?;
}
}
visitor.leave_region()
}
}
+12 -76
View File
@@ -19,7 +19,7 @@ use std::{
ops::{Index, IndexMut},
};
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Visit)]
pub struct KeyFrame {
pub position: Vector3<f32>,
pub scale: Vector3<f32>,
@@ -54,42 +54,18 @@ impl Default for KeyFrame {
}
}
impl Visit for KeyFrame {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.position.visit("Position", visitor)?;
self.scale.visit("Scale", visitor)?;
self.rotation.visit("Rotation", visitor)?;
self.time.visit("Time", visitor)?;
visitor.leave_region()
}
}
#[derive(Default, Copy, Clone, Debug)]
#[derive(Default, Copy, Clone, Debug, Visit)]
pub struct PoseEvaluationFlags {
pub ignore_position: bool,
pub ignore_rotation: bool,
pub ignore_scale: bool,
}
impl Visit for PoseEvaluationFlags {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.ignore_position.visit("IgnorePosition", visitor)?;
self.ignore_rotation.visit("IgnoreRotation", visitor)?;
self.ignore_scale.visit("IgnoreScale", visitor)?;
visitor.leave_region()
}
}
#[derive(Debug)]
#[derive(Debug, Visit)]
pub struct Track {
// Frames are not serialized, because it makes no sense to store them in save file,
// they will be taken from resource on Resolve stage.
#[visit(skip)]
frames: Vec<KeyFrame>,
enabled: bool,
max_time: f32,
@@ -121,19 +97,6 @@ impl Default for Track {
}
}
impl Visit for Track {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.enabled.visit("Enabled", visitor)?;
self.max_time.visit("MaxTime", visitor)?;
self.node.visit("Node", visitor)?;
self.flags.visit("Flags", visitor)?;
visitor.leave_region()
}
}
impl Track {
pub fn new() -> Track {
Default::default()
@@ -260,7 +223,7 @@ pub struct AnimationEvent {
pub signal_id: u64,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Visit)]
pub struct AnimationSignal {
id: u64,
time: f32,
@@ -303,19 +266,7 @@ impl Default for AnimationSignal {
}
}
impl Visit for AnimationSignal {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.id.visit("Id", visitor)?;
self.time.visit("Time", visitor)?;
self.enabled.visit("Enabled", visitor)?;
visitor.leave_region()
}
}
#[derive(Debug)]
#[derive(Debug, Visit)]
pub struct Animation {
// TODO: Extract into separate struct AnimationTimeline
tracks: Vec<Track>,
@@ -326,8 +277,10 @@ pub struct Animation {
looped: bool,
enabled: bool,
pub(in crate) resource: Option<Model>,
#[visit(skip)]
pose: AnimationPose,
signals: Vec<AnimationSignal>,
#[visit(skip)]
events: VecDeque<AnimationEvent>,
}
@@ -744,23 +697,6 @@ impl Default for Animation {
}
}
impl Visit for Animation {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.tracks.visit("Tracks", visitor)?;
self.speed.visit("Speed", visitor)?;
self.length.visit("Length", visitor)?;
self.time_position.visit("TimePosition", visitor)?;
self.resource.visit("Resource", visitor)?;
self.looped.visit("Looped", visitor)?;
self.enabled.visit("Enabled", visitor)?;
self.signals.visit("Signals", visitor)?;
visitor.leave_region()
}
}
#[derive(Debug, Clone)]
pub struct AnimationContainer {
pool: Pool<Animation>,
@@ -898,15 +834,15 @@ impl AnimationContainer {
impl Visit for AnimationContainer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
if visitor.is_reading() && self.pool.get_capacity() != 0 {
panic!("Animation pool must be empty on load!");
}
self.pool.visit("Pool", visitor)?;
let mut region = visitor.enter_region(name)?;
visitor.leave_region()
self.pool.visit("Pool", &mut region)?;
Ok(())
}
}
+5 -3
View File
@@ -49,9 +49,11 @@ pub struct ShaderState {
impl Visit for ShaderState {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.path.visit("Path", visitor)?;
self.path.visit("Path", &mut region)?;
drop(region);
if visitor.is_reading() {
if self.path == Path::new("Standard") {
@@ -61,7 +63,7 @@ impl Visit for ShaderState {
}
}
visitor.leave_region()
Ok(())
}
}
+3 -11
View File
@@ -51,10 +51,12 @@ pub(in crate) enum NodeMapping {
}
/// See module docs.
#[derive(Debug)]
#[derive(Debug, Visit)]
pub struct ModelData {
pub(in crate) path: PathBuf,
#[visit(skip)]
pub(in crate) mapping: NodeMapping,
#[visit(skip)]
scene: Scene,
}
@@ -232,16 +234,6 @@ impl Default for ModelData {
}
}
impl Visit for ModelData {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.path.visit("Path", visitor)?;
visitor.leave_region()
}
}
/// Defines a way of searching materials when loading a model resource from foreign file format such as FBX.
///
/// # Motivation
+31 -102
View File
@@ -88,7 +88,7 @@ impl Default for TextureKind {
impl Visit for TextureKind {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut id = match self {
TextureKind::Line { .. } => 0,
@@ -96,8 +96,8 @@ impl Visit for TextureKind {
TextureKind::Cube { .. } => 2,
TextureKind::Volume { .. } => 3,
};
id.visit("Id", visitor)?;
if visitor.is_reading() {
id.visit("Id", &mut region)?;
if region.is_reading() {
*self = match id {
0 => TextureKind::Line { length: 0 },
1 => TextureKind::Rectangle {
@@ -123,28 +123,28 @@ impl Visit for TextureKind {
}
match self {
TextureKind::Line { length } => {
length.visit("Length", visitor)?;
length.visit("Length", &mut region)?;
}
TextureKind::Rectangle { width, height } => {
width.visit("Width", visitor)?;
height.visit("Height", visitor)?;
width.visit("Width", &mut region)?;
height.visit("Height", &mut region)?;
}
TextureKind::Cube { width, height } => {
width.visit("Width", visitor)?;
height.visit("Height", visitor)?;
width.visit("Width", &mut region)?;
height.visit("Height", &mut region)?;
}
TextureKind::Volume {
width,
height,
depth,
} => {
width.visit("Width", visitor)?;
height.visit("Height", visitor)?;
depth.visit("Depth", visitor)?;
width.visit("Width", &mut region)?;
height.visit("Height", &mut region)?;
depth.visit("Depth", &mut region)?;
}
}
visitor.leave_region()
Ok(())
}
}
@@ -213,33 +213,35 @@ impl ResourceData for TextureData {
impl Visit for TextureData {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut kind = self.pixel_kind.id();
kind.visit("KindId", visitor)?;
if visitor.is_reading() {
kind.visit("KindId", &mut region)?;
if region.is_reading() {
self.pixel_kind = TexturePixelKind::new(kind)?;
}
self.path.visit("Path", visitor)?;
self.path.visit("Path", &mut region)?;
self.minification_filter
.visit("MinificationFilter", visitor)?;
.visit("MinificationFilter", &mut region)?;
self.magnification_filter
.visit("MagnificationFilter", visitor)?;
self.anisotropy.visit("Anisotropy", visitor)?;
self.s_wrap_mode.visit("SWrapMode", visitor)?;
self.t_wrap_mode.visit("TWrapMode", visitor)?;
self.mip_count.visit("MipCount", visitor)?;
self.kind.visit("Kind", visitor)?;
let _ = self.serialize_content.visit("SerializeContent", visitor);
.visit("MagnificationFilter", &mut region)?;
self.anisotropy.visit("Anisotropy", &mut region)?;
self.s_wrap_mode.visit("SWrapMode", &mut region)?;
self.t_wrap_mode.visit("TWrapMode", &mut region)?;
self.mip_count.visit("MipCount", &mut region)?;
self.kind.visit("Kind", &mut region)?;
let _ = self
.serialize_content
.visit("SerializeContent", &mut region);
if self.serialize_content {
let mut bytes_view = PodVecView::from_pod_vec(&mut self.bytes);
bytes_view.visit("Data", visitor)?;
bytes_view.visit("Data", &mut region)?;
}
visitor.leave_region()
Ok(())
}
}
@@ -488,6 +490,7 @@ impl Texture {
EnumVariantNames,
EnumString,
AsRefStr,
Visit,
)]
#[repr(u32)]
pub enum TextureMagnificationFilter {
@@ -506,30 +509,6 @@ impl Default for TextureMagnificationFilter {
}
}
impl Visit for TextureMagnificationFilter {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut id = *self as u32;
id.visit("Id", visitor)?;
if visitor.is_reading() {
*self = match id {
0 => TextureMagnificationFilter::Nearest,
1 => TextureMagnificationFilter::Linear,
_ => {
return VisitResult::Err(VisitError::User(format!(
"Invalid magnification filter {}!",
id
)))
}
}
}
visitor.leave_region()
}
}
/// The texture minifying function is used whenever the pixel being textured maps to an area
/// greater than one texture element.
#[derive(
@@ -545,6 +524,7 @@ impl Visit for TextureMagnificationFilter {
EnumVariantNames,
EnumString,
AsRefStr,
Visit,
)]
#[repr(u32)]
pub enum TextureMinificationFilter {
@@ -598,34 +578,6 @@ impl Default for TextureMinificationFilter {
}
}
impl Visit for TextureMinificationFilter {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut id = *self as u32;
id.visit("Id", visitor)?;
if visitor.is_reading() {
*self = match id {
0 => TextureMinificationFilter::Nearest,
1 => TextureMinificationFilter::NearestMipMapNearest,
2 => TextureMinificationFilter::NearestMipMapLinear,
3 => TextureMinificationFilter::Linear,
4 => TextureMinificationFilter::LinearMipMapNearest,
5 => TextureMinificationFilter::LinearMipMapLinear,
_ => {
return VisitResult::Err(VisitError::User(format!(
"Invalid minification filter {}!",
id
)))
}
}
}
visitor.leave_region()
}
}
/// Defines a law of texture coordinate modification.
#[derive(
Copy,
@@ -640,6 +592,7 @@ impl Visit for TextureMinificationFilter {
EnumVariantNames,
EnumString,
AsRefStr,
Visit,
)]
#[repr(u32)]
pub enum TextureWrapMode {
@@ -672,30 +625,6 @@ impl Default for TextureWrapMode {
}
}
impl Visit for TextureWrapMode {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut id = *self as u32;
id.visit("Id", visitor)?;
if visitor.is_reading() {
*self = match id {
0 => TextureWrapMode::Repeat,
1 => TextureWrapMode::ClampToEdge,
2 => TextureWrapMode::ClampToBorder,
3 => TextureWrapMode::MirroredRepeat,
4 => TextureWrapMode::MirrorClampToEdge,
_ => {
return VisitResult::Err(VisitError::User(format!("Invalid wrap mode {}!", id)))
}
}
}
visitor.leave_region()
}
}
/// Texture kind defines pixel format of texture.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(u32)]
+25 -25
View File
@@ -787,16 +787,16 @@ pub fn visit_opt_script(
script: &mut Option<Script>,
visitor: &mut Visitor,
) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut script_type_uuid = script.as_ref().map(|s| s.id()).unwrap_or_default();
script_type_uuid.visit("TypeUuid", visitor)?;
script_type_uuid.visit("TypeUuid", &mut region)?;
if visitor.is_reading() {
if region.is_reading() {
*script = if script_type_uuid.is_nil() {
None
} else {
let serialization_context = visitor
let serialization_context = region
.environment
.as_ref()
.and_then(|e| e.downcast_ref::<SerializationContext>())
@@ -817,34 +817,34 @@ pub fn visit_opt_script(
}
if let Some(script) = script {
script.visit("ScriptData", visitor)?;
script.visit("ScriptData", &mut region)?;
}
visitor.leave_region()
Ok(())
}
impl Visit for Base {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.name.visit("Name", visitor)?;
self.local_transform.visit("Transform", visitor)?;
self.visibility.visit("Visibility", visitor)?;
self.parent.visit("Parent", visitor)?;
self.children.visit("Children", visitor)?;
self.resource.visit("Resource", visitor)?;
self.name.visit("Name", &mut region)?;
self.local_transform.visit("Transform", &mut region)?;
self.visibility.visit("Visibility", &mut region)?;
self.parent.visit("Parent", &mut region)?;
self.children.visit("Children", &mut region)?;
self.resource.visit("Resource", &mut region)?;
self.is_resource_instance_root
.visit("IsResourceInstance", visitor)?;
self.lifetime.visit("Lifetime", visitor)?;
self.depth_offset.visit("DepthOffset", visitor)?;
self.lod_group.visit("LodGroup", visitor)?;
self.mobility.visit("Mobility", visitor)?;
.visit("IsResourceInstance", &mut region)?;
self.lifetime.visit("Lifetime", &mut region)?;
self.depth_offset.visit("DepthOffset", &mut region)?;
self.lod_group.visit("LodGroup", &mut region)?;
self.mobility.visit("Mobility", &mut region)?;
self.original_handle_in_resource
.visit("Original", visitor)?;
self.tag.visit("Tag", visitor)?;
let _ = self.properties.visit("Properties", visitor);
let _ = self.frustum_culling.visit("FrustumCulling", visitor);
let _ = self.cast_shadows.visit("CastShadows", visitor);
.visit("Original", &mut region)?;
self.tag.visit("Tag", &mut region)?;
let _ = self.properties.visit("Properties", &mut region);
let _ = self.frustum_culling.visit("FrustumCulling", &mut region);
let _ = self.cast_shadows.visit("CastShadows", &mut region);
// Script visiting may fail for various reasons:
//
@@ -854,7 +854,7 @@ impl Visit for Base {
//
// None of the reasons are fatal and we should still give an ability to load such node
// to edit or remove it.
if let Err(e) = visit_opt_script("Script", &mut self.script, visitor) {
if let Err(e) = visit_opt_script("Script", &mut self.script, &mut region) {
// Do not spam with error messages if there is missing `Script` field. It is ok
// for old scenes not to have script at all.
if !matches!(e, VisitError::RegionDoesNotExist(_)) {
@@ -862,7 +862,7 @@ impl Visit for Base {
}
}
visitor.leave_region()
Ok(())
}
}
+2 -16
View File
@@ -1009,7 +1009,7 @@ impl SkyBoxBuilder {
/// skies and/or some other objects (mountains, buildings, etc.). Usually skyboxes used
/// in outdoor scenes, however real use of it limited only by your imagination. Skybox
/// will be drawn first, none of objects could be drawn before skybox.
#[derive(Debug, Clone, Default, PartialEq, Inspect)]
#[derive(Debug, Clone, Default, PartialEq, Inspect, Visit)]
pub struct SkyBox {
/// Texture for front face.
pub(in crate) front: Option<Texture>,
@@ -1025,6 +1025,7 @@ pub struct SkyBox {
pub(in crate) bottom: Option<Texture>,
/// Cubemap texture
#[inspect(skip)]
#[visit(skip)]
pub(in crate) cubemap: Option<Texture>,
}
@@ -1172,18 +1173,3 @@ impl SkyBox {
self.back.clone()
}
}
impl Visit for SkyBox {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.left.visit("Left", visitor)?;
self.right.visit("Right", visitor)?;
self.top.visit("Top", visitor)?;
self.bottom.visit("Bottom", visitor)?;
self.front.visit("Front", visitor)?;
self.back.visit("Back", visitor)?;
visitor.leave_region()
}
}
+9 -9
View File
@@ -1240,21 +1240,21 @@ impl<'a> Iterator for GraphHandleTraverseIterator<'a> {
impl Visit for Graph {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
// Pool must be empty, otherwise handles will be invalid and everything will blow up.
if visitor.is_reading() && self.pool.get_capacity() != 0 {
panic!("Graph pool must be empty on load!")
}
self.root.visit("Root", visitor)?;
self.pool.visit("Pool", visitor)?;
// Backward compatibility
let _ = self.sound_context.visit("SoundContext", visitor);
let _ = self.physics.visit("PhysicsWorld", visitor);
let _ = self.physics2d.visit("PhysicsWorld2D", visitor);
let mut region = visitor.enter_region(name)?;
visitor.leave_region()
self.root.visit("Root", &mut region)?;
self.pool.visit("Pool", &mut region)?;
// Backward compatibility
let _ = self.sound_context.visit("SoundContext", &mut region);
let _ = self.physics.visit("PhysicsWorld", &mut region);
let _ = self.physics2d.visit("PhysicsWorld2D", &mut region);
Ok(())
}
}
+3 -16
View File
@@ -54,7 +54,7 @@ pub const DEFAULT_SCATTER_B: f32 = 0.03;
/// Light scene node. It contains common properties of light such as color,
/// scattering factor (per color channel) and other useful properties. Exact
/// behavior defined by specific light kind.
#[derive(Debug, Inspect, Clone)]
#[derive(Debug, Inspect, Clone, Visit)]
pub struct BaseLight {
base: Base,
@@ -65,12 +65,14 @@ pub struct BaseLight {
cast_shadows: TemplateVariable<bool>,
#[inspect(getter = "Deref::deref")]
#[visit(rename = "ScatterFactor")]
scatter: TemplateVariable<Vector3<f32>>,
#[inspect(getter = "Deref::deref")]
scatter_enabled: TemplateVariable<bool>,
#[inspect(min_value = 0.0, step = 0.1, getter = "Deref::deref")]
#[visit(optional)]
intensity: TemplateVariable<f32>,
}
@@ -113,21 +115,6 @@ impl Default for BaseLight {
}
}
impl Visit for BaseLight {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.color.visit("Color", visitor)?;
self.base.visit("Base", visitor)?;
self.cast_shadows.visit("CastShadows", visitor)?;
self.scatter.visit("ScatterFactor", visitor)?;
self.scatter_enabled.visit("ScatterEnabled", visitor)?;
let _ = self.intensity.visit("Intensity", visitor); // Backward compatibility.
visitor.leave_region()
}
}
impl BaseLight {
/// Sets color of light, alpha component of color is ignored.
#[inline]
+1 -13
View File
@@ -40,7 +40,7 @@ use fxhash::FxHashMap;
use std::ops::{Deref, DerefMut};
/// See module docs.
#[derive(Debug, Inspect, Clone)]
#[derive(Debug, Inspect, Clone, Visit)]
pub struct PointLight {
base_light: BaseLight,
@@ -149,18 +149,6 @@ impl NodeTrait for PointLight {
}
}
impl Visit for PointLight {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.base_light.visit("BaseLight", visitor)?;
self.radius.visit("Radius", visitor)?;
self.shadow_bias.visit("ShadowBias", visitor)?;
visitor.leave_region()
}
}
impl Default for PointLight {
fn default() -> Self {
Self {
+1 -17
View File
@@ -46,7 +46,7 @@ use fxhash::FxHashMap;
use std::ops::{Deref, DerefMut};
/// See module docs.
#[derive(Debug, Inspect, Clone)]
#[derive(Debug, Inspect, Clone, Visit)]
pub struct SpotLight {
base_light: BaseLight,
@@ -244,22 +244,6 @@ impl NodeTrait for SpotLight {
}
}
impl Visit for SpotLight {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.base_light.visit("BaseLight", visitor)?;
self.hotspot_cone_angle.visit("HotspotConeAngle", visitor)?;
self.falloff_angle_delta
.visit("FalloffAngleDelta", visitor)?;
self.distance.visit("Distance", visitor)?;
self.shadow_bias.visit("ShadowBias", visitor)?;
self.cookie_texture.visit("CookieTexture", visitor)?;
visitor.leave_region()
}
}
/// Allows you to build spot light in declarative manner.
pub struct SpotLightBuilder {
base_light_builder: BaseLightBuilder,
+16 -22
View File
@@ -847,32 +847,37 @@ impl SurfaceData {
impl Visit for SurfaceData {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.is_procedural.visit("IsProcedural", visitor)?;
self.is_procedural.visit("IsProcedural", &mut region)?;
if self.is_procedural {
if self.vertex_buffer.visit("VertexBuffer", visitor).is_err() && visitor.is_reading() {
if self
.vertex_buffer
.visit("VertexBuffer", &mut region)
.is_err()
&& region.is_reading()
{
// Backward compatibility
let mut old_vertices = Vec::<OldVertex>::new();
old_vertices.visit("Vertices", visitor)?;
old_vertices.visit("Vertices", &mut region)?;
self.vertex_buffer =
VertexBuffer::new(old_vertices.len(), OldVertex::layout(), old_vertices)
.unwrap();
};
if self
.geometry_buffer
.visit("GeometryBuffer", visitor)
.visit("GeometryBuffer", &mut region)
.is_err()
&& visitor.is_reading()
&& region.is_reading()
{
let mut triangles = Vec::<TriangleDefinition>::new();
triangles.visit("Triangles", visitor)?;
triangles.visit("Triangles", &mut region)?;
self.geometry_buffer = TriangleBuffer::new(triangles);
}
}
visitor.leave_region()
Ok(())
}
}
@@ -955,11 +960,12 @@ impl VertexWeightSet {
}
/// See module docs.
#[derive(Debug, Clone, Inspect)]
#[derive(Debug, Clone, Inspect, Visit)]
pub struct Surface {
// Wrapped into option to be able to implement Default for serialization.
// In normal conditions it must never be None!
data: Option<Arc<Mutex<SurfaceData>>>,
#[visit(optional)]
material: Arc<Mutex<Material>>,
/// Temporal array for FBX conversion needs, it holds skinning data (weight + bone handle)
/// and will be used to fill actual bone indices and weight in vertices that will be
@@ -968,6 +974,7 @@ pub struct Surface {
/// like so: iterate over all vertices and weight data and calculate index of node handle that
/// associated with vertex in `bones` array and store it as bone index in vertex.
#[inspect(skip)]
#[visit(skip)]
pub vertex_weights: Vec<VertexWeightSet>,
/// Array of handle to scene nodes which are used as bones.
pub bones: Vec<Handle<Node>>,
@@ -1047,19 +1054,6 @@ impl Surface {
}
}
impl Visit for Surface {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
// self.vertex_weights intentionally not serialized!
self.data.visit("Data", visitor)?;
self.bones.visit("Bones", visitor)?;
let _ = self.material.visit("Material", visitor); // Backward compatibility.
visitor.leave_region()
}
}
/// Surface builder allows you to create surfaces in declarative manner.
pub struct SurfaceBuilder {
data: Arc<Mutex<SurfaceData>>,
+15 -15
View File
@@ -292,25 +292,25 @@ pub struct OldVertex {
impl Visit for OldVertex {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.position.visit("Position", visitor)?;
self.tex_coord.visit("TexCoord", visitor)?;
self.second_tex_coord.visit("SecondTexCoord", visitor)?;
self.normal.visit("Normal", visitor)?;
self.tangent.visit("Tangent", visitor)?;
self.position.visit("Position", &mut region)?;
self.tex_coord.visit("TexCoord", &mut region)?;
self.second_tex_coord.visit("SecondTexCoord", &mut region)?;
self.normal.visit("Normal", &mut region)?;
self.tangent.visit("Tangent", &mut region)?;
self.bone_weights[0].visit("Weight0", visitor)?;
self.bone_weights[1].visit("Weight1", visitor)?;
self.bone_weights[2].visit("Weight2", visitor)?;
self.bone_weights[3].visit("Weight3", visitor)?;
self.bone_weights[0].visit("Weight0", &mut region)?;
self.bone_weights[1].visit("Weight1", &mut region)?;
self.bone_weights[2].visit("Weight2", &mut region)?;
self.bone_weights[3].visit("Weight3", &mut region)?;
self.bone_indices[0].visit("BoneIndex0", visitor)?;
self.bone_indices[1].visit("BoneIndex1", visitor)?;
self.bone_indices[2].visit("BoneIndex2", visitor)?;
self.bone_indices[3].visit("BoneIndex3", visitor)?;
self.bone_indices[0].visit("BoneIndex0", &mut region)?;
self.bone_indices[1].visit("BoneIndex1", &mut region)?;
self.bone_indices[2].visit("BoneIndex2", &mut region)?;
self.bone_indices[3].visit("BoneIndex3", &mut region)?;
visitor.leave_region()
Ok(())
}
}
+12 -20
View File
@@ -142,7 +142,7 @@ macro_rules! impl_directly_inheritable_entity_trait {
}
/// A container for navigational meshes.
#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, Visit)]
pub struct NavMeshContainer {
pool: Pool<Navmesh>,
}
@@ -218,16 +218,6 @@ impl IndexMut<Handle<Navmesh>> for NavMeshContainer {
}
}
impl Visit for NavMeshContainer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.pool.visit("Pool", visitor)?;
visitor.leave_region()
}
}
/// See module docs.
#[derive(Debug)]
pub struct Scene {
@@ -692,18 +682,20 @@ impl Scene {
}
fn visit(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(region_name)?;
let mut region = visitor.enter_region(region_name)?;
self.graph.visit("Graph", visitor)?;
self.animations.visit("Animations", visitor)?;
self.lightmap.visit("Lightmap", visitor)?;
self.navmeshes.visit("NavMeshes", visitor)?;
self.graph.visit("Graph", &mut region)?;
self.animations.visit("Animations", &mut region)?;
self.lightmap.visit("Lightmap", &mut region)?;
self.navmeshes.visit("NavMeshes", &mut region)?;
self.ambient_lighting_color
.visit("AmbientLightingColor", visitor)?;
self.enabled.visit("Enabled", visitor)?;
let _ = self.animation_machines.visit("AnimationMachines", visitor);
.visit("AmbientLightingColor", &mut region)?;
self.enabled.visit("Enabled", &mut region)?;
let _ = self
.animation_machines
.visit("AnimationMachines", &mut region);
visitor.leave_region()
Ok(())
}
/// Saves scene in a specified file.
+16 -21
View File
@@ -37,10 +37,10 @@ fn read_node(name: &str, visitor: &mut Visitor) -> Result<Node, VisitError> {
let mut node = match kind_id {
0 => Node::new(Pivot::default()),
1 => {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut light_id = 0u32;
light_id.visit("KindId", visitor)?;
light_id.visit("KindId", &mut region)?;
let mut light_node = match light_id {
0 => Node::new(SpotLight::default()),
@@ -54,9 +54,7 @@ fn read_node(name: &str, visitor: &mut Visitor) -> Result<Node, VisitError> {
}
};
light_node.visit("Data", visitor)?;
visitor.leave_region()?;
light_node.visit("Data", &mut region)?;
return Ok(light_node);
}
@@ -88,12 +86,12 @@ fn read_node(name: &str, visitor: &mut Visitor) -> Result<Node, VisitError> {
node
} else {
// Latest version
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut id = Uuid::default();
id.visit("TypeUuid", visitor)?;
id.visit("TypeUuid", &mut region)?;
let serialization_context = visitor
let serialization_context = region
.environment
.as_ref()
.and_then(|e| e.downcast_ref::<SerializationContext>())
@@ -104,9 +102,7 @@ fn read_node(name: &str, visitor: &mut Visitor) -> Result<Node, VisitError> {
.try_create(&id)
.ok_or_else(|| VisitError::User(format!("Unknown node type uuid {}!", id)))?;
node.visit("NodeData", visitor)?;
visitor.leave_region()?;
node.visit("NodeData", &mut region)?;
node
}
@@ -116,32 +112,31 @@ fn read_node(name: &str, visitor: &mut Visitor) -> Result<Node, VisitError> {
}
fn write_node(name: &str, node: &mut Node, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut id = node.id();
id.visit("TypeUuid", visitor)?;
id.visit("TypeUuid", &mut region)?;
node.visit("NodeData", visitor)?;
node.visit("NodeData", &mut region)?;
visitor.leave_region()
Ok(())
}
impl Visit for NodeContainer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut is_some = if self.is_some() { 1u8 } else { 0u8 };
is_some.visit("IsSome", visitor)?;
is_some.visit("IsSome", &mut region)?;
if is_some != 0 {
if visitor.is_reading() {
*self = NodeContainer(Some(read_node("Data", visitor)?));
if region.is_reading() {
*self = NodeContainer(Some(read_node("Data", &mut region)?));
} else {
write_node("Data", self.0.as_mut().unwrap(), visitor)?;
write_node("Data", self.0.as_mut().unwrap(), &mut region)?;
}
}
visitor.leave_region()?;
Ok(())
}
}
+5 -3
View File
@@ -119,14 +119,16 @@ pub enum ParticleLimit {
impl Visit for ParticleLimit {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut amount = match self {
Self::Unlimited => -1,
Self::Strict(value) => *value as i32,
};
amount.visit("Amount", visitor)?;
amount.visit("Amount", &mut region)?;
drop(region);
if visitor.is_reading() {
*self = if amount < 0 {
@@ -136,7 +138,7 @@ impl Visit for ParticleLimit {
};
}
visitor.leave_region()
Ok(())
}
}
+10 -8
View File
@@ -93,19 +93,21 @@ pub struct Chunk {
// Manual implementation of the trait because we need to serialize heightmap differently.
impl Visit for Chunk {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
let mut view = PodVecView::from_pod_vec(&mut self.heightmap);
view.visit("Heightmap", visitor)?;
view.visit("Heightmap", &mut region)?;
self.position.visit("Position", visitor)?;
self.width.visit("Width", visitor)?;
self.length.visit("Length", visitor)?;
self.width_point_count.visit("WidthPointCount", visitor)?;
self.length_point_count.visit("LengthPointCount", visitor)?;
self.position.visit("Position", &mut region)?;
self.width.visit("Width", &mut region)?;
self.length.visit("Length", &mut region)?;
self.width_point_count
.visit("WidthPointCount", &mut region)?;
self.length_point_count
.visit("LengthPointCount", &mut region)?;
// self.surface_data, self.dirty is are not serialized.
visitor.leave_region()
Ok(())
}
}
+13 -11
View File
@@ -136,24 +136,26 @@ impl_directly_inheritable_entity_trait!(Transform;
impl Visit for Transform {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.local_scale.visit("LocalScale", visitor)?;
self.local_position.visit("LocalPosition", visitor)?;
self.local_rotation.visit("LocalRotation", visitor)?;
self.pre_rotation.visit("PreRotation", visitor)?;
self.post_rotation.visit("PostRotation", visitor)?;
self.rotation_offset.visit("RotationOffset", visitor)?;
self.rotation_pivot.visit("RotationPivot", visitor)?;
self.scaling_offset.visit("ScalingOffset", visitor)?;
self.scaling_pivot.visit("ScalingPivot", visitor)?;
self.local_scale.visit("LocalScale", &mut region)?;
self.local_position.visit("LocalPosition", &mut region)?;
self.local_rotation.visit("LocalRotation", &mut region)?;
self.pre_rotation.visit("PreRotation", &mut region)?;
self.post_rotation.visit("PostRotation", &mut region)?;
self.rotation_offset.visit("RotationOffset", &mut region)?;
self.rotation_pivot.visit("RotationPivot", &mut region)?;
self.scaling_offset.visit("ScalingOffset", &mut region)?;
self.scaling_pivot.visit("ScalingPivot", &mut region)?;
drop(region);
if visitor.is_reading() {
self.post_rotation_matrix =
build_post_rotation_matrix(self.post_rotation.clone_inner());
}
visitor.leave_region()
Ok(())
}
}
+10 -15
View File
@@ -298,34 +298,29 @@ where
Ok(())
} else {
// Reading the latest version.
if visitor
.current_region()
.map(|region| region != name)
.unwrap_or_default()
{
visitor.enter_region(name)?;
}
self.value.visit("Value", visitor)?;
let mut region = visitor.enter_region(name)?;
self.value.visit("Value", &mut region)?;
// We still might have old version with single IsCustom flag.
let mut is_custom = false;
if is_custom.visit("IsCustom", visitor).is_ok() {
if is_custom.visit("IsCustom", &mut region).is_ok() {
self.flags.get_mut().set(VariableFlags::MODIFIED, is_custom);
} else {
self.flags.get_mut().bits.visit("Flags", visitor)?;
self.flags.get_mut().bits.visit("Flags", &mut region)?;
}
visitor.leave_region()
Ok(())
}
} else {
// Write in latest format.
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.value.visit("Value", visitor)?;
self.flags.get_mut().bits.visit("Flags", visitor)?;
self.value.visit("Value", &mut region)?;
self.flags.get_mut().bits.visit("Flags", &mut region)?;
visitor.leave_region()
Ok(())
}
}
}
+6 -24
View File
@@ -20,13 +20,17 @@ enum PathVertexState {
/// Graph vertex that contains position in world and list of indices of neighbour
/// vertices.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Visit)]
pub struct PathVertex {
/// Position in world.
pub position: Vector3<f32>,
#[visit(skip)]
state: PathVertexState,
#[visit(skip)]
g_score: f32,
#[visit(skip)]
f_score: f32,
#[visit(skip)]
parent: Option<usize>,
neighbours: Vec<u32>,
}
@@ -44,18 +48,6 @@ impl Default for PathVertex {
}
}
impl Visit for PathVertex {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.position.visit("Position", visitor)?;
self.neighbours.visit("Neighbours", visitor)?;
// Rest of fields are runtime state and valid only while in a build method of pathfinder.
visitor.leave_region()
}
}
impl PathVertex {
/// Creates new vertex at given position.
pub fn new(position: Vector3<f32>) -> Self {
@@ -83,21 +75,11 @@ impl PathVertex {
}
/// See module docs.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Visit)]
pub struct PathFinder {
vertices: Vec<PathVertex>,
}
impl Visit for PathFinder {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.vertices.visit("Vertices", visitor)?;
visitor.leave_region()
}
}
/// Shows path status.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PathKind {
+2 -24
View File
@@ -48,7 +48,7 @@ use std::{
};
///
#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, Visit)]
pub struct LightmapEntry {
/// Lightmap texture.
///
@@ -62,19 +62,8 @@ pub struct LightmapEntry {
pub lights: Vec<Handle<Node>>,
}
impl Visit for LightmapEntry {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.texture.visit("Texture", visitor)?;
self.lights.visit("Lights", visitor)?;
visitor.leave_region()
}
}
/// Lightmap is a texture with precomputed lighting.
#[derive(Default, Clone, Debug)]
#[derive(Default, Clone, Debug, Visit)]
pub struct Lightmap {
/// Node handle to lightmap mapping. It is used to quickly get information about
/// lightmaps for any node in scene.
@@ -85,17 +74,6 @@ pub struct Lightmap {
pub patches: FxHashMap<u64, SurfaceDataPatch>,
}
impl Visit for Lightmap {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.map.visit("Map", visitor)?;
self.patches.visit("Patches", visitor)?;
visitor.leave_region()
}
}
struct WorldVertex {
world_normal: Vector3<f32>,
world_position: Vector3<f32>,
+7 -24
View File
@@ -37,10 +37,12 @@ pub struct Navmesh {
impl Visit for Navmesh {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
let mut region = visitor.enter_region(name)?;
self.pathfinder.visit("PathFinder", visitor)?;
self.triangles.visit("Triangles", visitor)?;
self.pathfinder.visit("PathFinder", &mut region)?;
self.triangles.visit("Triangles", &mut region)?;
drop(region);
// No need to save octree, we can restore it on load.
if visitor.is_reading() {
@@ -60,7 +62,7 @@ impl Visit for Navmesh {
self.octree = Octree::new(&raw_triangles, 32);
}
visitor.leave_region()
Ok(())
}
}
@@ -305,6 +307,7 @@ impl Navmesh {
/// Navmesh agent is a "pathfinding unit" that performs navigation on a mesh. It is designed to
/// cover most of simple use cases when you need to build and follow some path from point A to point B.
#[derive(Visit)]
pub struct NavmeshAgent {
path: Vec<Vector3<f32>>,
current: u32,
@@ -317,26 +320,6 @@ pub struct NavmeshAgent {
path_dirty: bool,
}
impl Visit for NavmeshAgent {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.path.visit("Path", visitor)?;
self.current.visit("Current", visitor)?;
self.position.visit("Position", visitor)?;
self.last_warp_position.visit("LastWarpPosition", visitor)?;
self.target.visit("Target", visitor)?;
self.last_target_position
.visit("LastTargetPosition", visitor)?;
self.recalculation_threshold
.visit("RecalculationThreshold", visitor)?;
self.speed.visit("Speed", visitor)?;
self.path_dirty.visit("PathDirty", visitor)?;
visitor.leave_region()
}
}
impl Default for NavmeshAgent {
fn default() -> Self {
Self::new()
+1 -15
View File
@@ -116,7 +116,7 @@ fn make_seam(
/// it just does not have secondary texture coordinates. So we have to patch data after
/// loading somehow with required data, this is where `SurfaceDataPatch` comes into
/// play.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Visit)]
pub struct SurfaceDataPatch {
/// A surface data id. Usually it is just a hash of surface data.
pub data_id: u64,
@@ -130,20 +130,6 @@ pub struct SurfaceDataPatch {
pub additional_vertices: Vec<u32>,
}
impl Visit for SurfaceDataPatch {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
visitor.enter_region(name)?;
self.data_id.visit("DataId", visitor)?;
self.triangles.visit("Triangles", visitor)?;
self.second_tex_coords.visit("SecondTexCoords", visitor)?;
self.additional_vertices
.visit("AdditionalVertices", visitor)?;
visitor.leave_region()
}
}
/// Maps each triangle from surface to appropriate side of box. This is so called
/// box mapping.
fn generate_uv_box(data: &SurfaceData) -> UvBox {