mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
use RegionGuard instead of manual call of pair enter/leave_region
This commit is contained in:
@@ -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
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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
@@ -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,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
@@ -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
@@ -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");
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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]
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user