[BREAKING] drop backward compatibility for assets

- use this tool from 1.0.0-rc.1  https://fyrox.rs/blog/post/fyrox-game-engine-1-0-0-rc-1/#migration to migrate the assets
This commit is contained in:
Dmitry Stepanov
2025-11-02 19:48:19 +03:00
parent f03f55f68b
commit ddd7a17fc8
32 changed files with 133 additions and 1120 deletions
+9 -74
View File
@@ -25,6 +25,7 @@
#![allow(clippy::doc_lazy_continuation)]
#![allow(mismatched_lifetime_syntaxes)]
use crate::track::TrackBinding;
use crate::{
core::{
algebra::{UnitQuaternion, Vector3},
@@ -39,7 +40,11 @@ use crate::{
track::Track,
};
use fxhash::FxHashMap;
pub use fyrox_core as core;
use fyrox_resource::untyped::ResourceKind;
use fyrox_resource::{Resource, ResourceData};
pub use pose::{AnimationPose, NodePose};
pub use signal::{AnimationEvent, AnimationSignal};
use std::{
collections::VecDeque,
error::Error,
@@ -50,13 +55,6 @@ use std::{
};
use value::{nlerp, TrackValue, ValueBinding};
use crate::container::TrackDataContainer;
use crate::track::TrackBinding;
pub use fyrox_core as core;
use fyrox_resource::untyped::ResourceKind;
pub use pose::{AnimationPose, NodePose};
pub use signal::{AnimationEvent, AnimationSignal};
pub mod container;
pub mod machine;
pub mod pose;
@@ -268,7 +266,7 @@ pub type AnimationTracksDataResource = Resource<AnimationTracksData>;
/// The code above creates a simple animation that moves a node along X axis in various ways. The usage of the animation
/// is only for the sake of completeness of the example. In the real games you need to add the animation to an animation
/// player scene node and it will do the job for you.
#[derive(Debug, Reflect, PartialEq)]
#[derive(Debug, Reflect, Visit, PartialEq)]
pub struct Animation<T: EntityId> {
name: ImmutableString,
tracks_data: AnimationTracksDataResource,
@@ -283,79 +281,16 @@ pub struct Animation<T: EntityId> {
max_event_capacity: usize,
#[reflect(hidden)]
#[visit(skip)]
root_motion: Option<RootMotion>,
// Non-serialized
#[reflect(hidden)]
#[visit(skip)]
pose: AnimationPose<T>,
// Non-serialized
#[reflect(hidden)]
#[visit(skip)]
events: VecDeque<AnimationEvent>,
}
#[derive(Visit, Default)]
struct OldTrack<T: EntityId> {
binding: ValueBinding,
frames: TrackDataContainer,
enabled: bool,
node: T,
id: Uuid,
}
impl<T: EntityId> Visit for Animation<T> {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
// Backward compatibility.
let mut old_tracks = Vec::<OldTrack<T>>::new();
if region.is_reading() {
if old_tracks.visit("Tracks", &mut region).is_ok() {
let mut tracks_data = AnimationTracksData::default();
for old_track in old_tracks {
self.track_bindings.insert(
old_track.id,
TrackBinding {
enabled: old_track.enabled,
target: old_track.node,
},
);
tracks_data.tracks.push(Track {
binding: old_track.binding,
frames: old_track.frames,
id: old_track.id,
});
}
self.tracks_data = AnimationTracksDataResource::new_ok(
Uuid::new_v4(),
ResourceKind::Embedded,
tracks_data,
);
} else {
self.tracks_data.visit("TracksData", &mut region)?;
self.track_bindings.visit("TrackBindings", &mut region)?;
}
} else {
self.tracks_data.visit("TracksData", &mut region)?;
self.track_bindings.visit("TrackBindings", &mut region)?;
}
let _ = self.name.visit("Name", &mut region);
self.time_position.visit("TimePosition", &mut region)?;
let _ = self.time_slice.visit("TimeSlice", &mut region);
self.speed.visit("Speed", &mut region)?;
self.looped.visit("Looped", &mut region)?;
self.enabled.visit("Enabled", &mut region)?;
self.signals.visit("Signals", &mut region)?;
let _ = self
.max_event_capacity
.visit("MaxEventCapacity", &mut region);
let _ = self
.root_motion_settings
.visit("RootMotionSettings", &mut region);
Ok(())
}
}
impl<T: EntityId> TypeUuidProvider for Animation<T> {
fn type_uuid() -> Uuid {
uuid!("aade8e9d-e2cf-401d-a4d1-59c6943645f3")
+1 -13
View File
@@ -88,25 +88,13 @@ impl<T: EntityId> TrackBinding<T> {
/// Track is responsible in animating a property of a single scene node. The track consists up to 4 parametric curves
/// that contains the actual property data. Parametric curves allows the engine to perform various interpolations between
/// key values.
#[derive(Debug, Reflect, Clone, PartialEq)]
#[derive(Debug, Reflect, Clone, PartialEq, Visit)]
pub struct Track {
pub(super) binding: ValueBinding,
pub(super) frames: TrackDataContainer,
pub(super) id: Uuid,
}
impl Visit for Track {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
let _ = self.binding.visit("Binding", &mut region); // Backward compatibility
let _ = self.id.visit("Id", &mut region); // Backward compatibility
let _ = self.frames.visit("Frames", &mut region); // Backward compatibility
Ok(())
}
}
impl Default for Track {
fn default() -> Self {
Self {
-2
View File
@@ -168,9 +168,7 @@ impl_reflect!(
impl_visit!(
pub struct Curve {
#[visit(optional)] // Backward compatibility
pub id: Uuid,
#[visit(optional)] // Backward compatibility
pub name: String,
pub keys: Vec<CurveKey>,
}
+3 -15
View File
@@ -18,7 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use crate::visitor::VisitorVersion;
use crate::{
replace_slashes,
visitor::{
@@ -158,20 +157,9 @@ where
if region.reading {
self.clear();
for index in 0..len as usize {
// Backward compatibility with the previous version (verbose, non-flat).
if region.version == VisitorVersion::Legacy as u32 {
if let Ok(mut item_region) = region.enter_region(&make_name(index)) {
let mut object = T::default();
object.visit("ItemData", &mut item_region)?;
self.push(object);
continue;
}
} else {
// Try to read the new (flattened) version.
let mut object = T::default();
object.visit(&make_name(index), &mut region)?;
self.push(object);
}
let mut object = T::default();
object.visit(&make_name(index), &mut region)?;
self.push(object);
}
} else {
for (index, item) in self.iter_mut().enumerate() {
+4 -18
View File
@@ -83,12 +83,8 @@ use std::{
/// Version of the visitor.
#[repr(u32)]
pub enum VisitorVersion {
/// Version of the old format.
Legacy = 0,
/// Flattened vector structure.
VectorFlattening,
/// Removal of `[N:` and `{N:` counters in ascii format.
AsciiNoCounters,
/// The first stable release of Fyrox 1.0.
FirstStableRelease,
/// ^^ Add a new version above this line ^^.
///
@@ -475,9 +471,6 @@ pub enum Format {
}
impl Visitor {
/// Old header marker for binary version.
pub const MAGIC_BINARY_OLD: &'static str = "RG3D";
/// Sequence of bytes that is automatically written at the start when a visitor is encoded into
/// bytes. It is written by [Visitor::save_binary_to_file], [Visitor::save_binary_to_memory],
/// and [Visitor::save_binary_to_vec].
@@ -487,9 +480,6 @@ impl Visitor {
/// these bytes are not at the beginning of the given slice.
pub const MAGIC_BINARY_CURRENT: &'static str = "FBAF";
/// Old header marker for ASCII version.
pub const MAGIC_ASCII_OLD: &'static str = "FTAF";
/// Sequence of bytes that is automatically written at the start when a visitor is encoded into
/// ascii form. It is written by [Visitor::save_ascii_to_file], [Visitor::save_ascii_to_memory],
/// and [Visitor::save_ascii_to_string].
@@ -509,13 +499,9 @@ impl Visitor {
pub fn detect_format(src: &mut dyn Read) -> Format {
let mut magic: [u8; 4] = Default::default();
if src.read_exact(&mut magic).is_ok() {
if magic.eq(Visitor::MAGIC_BINARY_OLD.as_bytes())
|| magic.eq(Visitor::MAGIC_BINARY_CURRENT.as_bytes())
{
if magic.eq(Visitor::MAGIC_BINARY_CURRENT.as_bytes()) {
return Format::Binary;
} else if magic.eq(Visitor::MAGIC_ASCII_OLD.as_bytes())
|| magic.eq(Visitor::MAGIC_ASCII_CURRENT.as_bytes())
{
} else if magic.eq(Visitor::MAGIC_ASCII_CURRENT.as_bytes()) {
return Format::Ascii;
}
}
+16 -37
View File
@@ -18,7 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use crate::visitor::VisitorVersion;
use crate::{
pool::{Handle, Pool},
visitor::{
@@ -332,47 +331,29 @@ impl Reader for AsciiReader<'_> {
..VisitorNode::default()
};
if visitor.version < VisitorVersion::AsciiNoCounters as u32 {
let field_count: usize = self.src.read_num_until(b':')?;
for _ in 0..field_count {
node.fields.push(self.read_field()?);
}
self.src.skip_until(|ch| ch != b']')?;
self.src.skip_n(1)?;
} else {
loop {
self.src.skip_ws()?;
let next = self.src.peek()?;
if next == b']' {
self.src.skip_n(1)?;
break;
}
node.fields.push(self.read_field()?);
loop {
self.src.skip_ws()?;
let next = self.src.peek()?;
if next == b']' {
self.src.skip_n(1)?;
break;
}
node.fields.push(self.read_field()?);
}
self.src.skip_until(|ch| ch != b'{')?;
self.src.skip_n(1)?;
let mut children = Vec::new();
if visitor.version < VisitorVersion::AsciiNoCounters as u32 {
let child_count: usize = self.src.read_num_until(b':')?;
children.reserve(child_count);
for _ in 0..child_count {
children.push(self.read_node(visitor)?);
}
self.src.skip_until(|ch| ch != b'}')?;
self.src.skip_n(1)?;
} else {
loop {
self.src.skip_ws()?;
let next = self.src.peek()?;
if next == b'}' {
self.src.skip_n(1)?;
break;
}
children.push(self.read_node(visitor)?);
loop {
self.src.skip_ws()?;
let next = self.src.peek()?;
if next == b'}' {
self.src.skip_n(1)?;
break;
}
children.push(self.read_node(visitor)?);
}
node.children.clone_from(&children);
@@ -391,9 +372,7 @@ impl Reader for AsciiReader<'_> {
let magic: [u8; 4] = [src.next()?, src.next()?, src.next()?, src.next()?];
let version = if magic.eq(Visitor::MAGIC_ASCII_OLD.as_bytes()) {
VisitorVersion::Legacy as u32
} else if magic.eq(Visitor::MAGIC_ASCII_CURRENT.as_bytes()) {
let version = if magic.eq(Visitor::MAGIC_ASCII_CURRENT.as_bytes()) {
src.skip_until(|ch| ch != b':')?;
src.skip_n(1)?;
src.read_num_until::<u32, _>(b';')?
+1 -4
View File
@@ -18,7 +18,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
use crate::visitor::VisitorVersion;
use crate::{
pool::{Handle, Pool},
visitor::{
@@ -246,9 +245,7 @@ impl Reader for BinaryReader<'_> {
let mut magic: [u8; 4] = Default::default();
src.read_exact(&mut magic)?;
let version = if magic.eq(Visitor::MAGIC_BINARY_OLD.as_bytes()) {
VisitorVersion::Legacy as u32
} else if magic.eq(Visitor::MAGIC_BINARY_CURRENT.as_bytes()) {
let version = if magic.eq(Visitor::MAGIC_BINARY_CURRENT.as_bytes()) {
src.read_u32::<LittleEndian>()?
} else {
return Err(VisitError::NotSupportedFormat);
+3 -2
View File
@@ -21,7 +21,7 @@
//! Curve resource holds a [`Curve`]
use crate::{
asset::{io::ResourceIo, Resource, ResourceData, CURVE_RESOURCE_UUID},
asset::{io::ResourceIo, Resource, ResourceData},
core::{
io::FileError, math::curve::Curve, reflect::prelude::*, uuid::Uuid, visitor::prelude::*,
TypeUuidProvider,
@@ -32,6 +32,7 @@ use std::{
fmt::{Display, Formatter},
path::Path,
};
use uuid::uuid;
pub mod loader;
@@ -101,7 +102,7 @@ impl ResourceData for CurveResourceState {
impl TypeUuidProvider for CurveResourceState {
fn type_uuid() -> Uuid {
CURVE_RESOURCE_UUID
uuid!("f28b949f-28a2-4b68-9089-59c234f58b6b")
}
}
+3 -2
View File
@@ -41,7 +41,7 @@
use crate::{
asset::{
io::ResourceIo, manager::ResourceManager, options::ImportOptions, untyped::ResourceKind,
Resource, ResourceData, MODEL_RESOURCE_UUID,
Resource, ResourceData,
},
core::{
algebra::{UnitQuaternion, Vector3},
@@ -76,6 +76,7 @@ use std::{
sync::Arc,
};
use strum_macros::{AsRefStr, EnumString, VariantNames};
use uuid::uuid;
pub mod loader;
@@ -104,7 +105,7 @@ impl PrefabData for Model {
impl TypeUuidProvider for Model {
fn type_uuid() -> Uuid {
MODEL_RESOURCE_UUID
uuid!("44cd768f-b4ca-4804-a98c-0adf85577ada")
}
}
+7 -23
View File
@@ -1188,14 +1188,7 @@ impl Visit for Base {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
if self.name.visit("Name", &mut region).is_err() {
// Name was wrapped into `InheritableVariable` previously, so we must maintain
// backward compatibility here.
let mut region = region.enter_region("Name")?;
let mut value = String::default();
value.visit("Value", &mut region)?;
self.name = ImmutableString::new(value);
}
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)?;
@@ -1209,12 +1202,12 @@ impl Visit for Base {
self.original_handle_in_resource
.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);
let _ = self.instance_id.visit("InstanceId", &mut region);
let _ = self.enabled.visit("Enabled", &mut region);
let _ = self.render_mask.visit("RenderMask", &mut region);
self.properties.visit("Properties", &mut region)?;
self.frustum_culling.visit("FrustumCulling", &mut region)?;
self.cast_shadows.visit("CastShadows", &mut region)?;
self.instance_id.visit("InstanceId", &mut region)?;
self.enabled.visit("Enabled", &mut region)?;
self.render_mask.visit("RenderMask", &mut region)?;
// Script visiting may fail for various reasons:
//
@@ -1225,15 +1218,6 @@ 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.
// This block is needed for backward compatibility
let mut old_script = None;
if region.is_reading() && visit_opt_script("Script", &mut old_script, &mut region).is_ok() {
if let Some(old_script) = old_script {
self.scripts.push(ScriptRecord::new(old_script));
}
return Ok(());
}
let _ = self.scripts.visit("Scripts", &mut region);
Ok(())
-6
View File
@@ -58,11 +58,9 @@ use strum_macros::{AsRefStr, EnumString, VariantNames};
#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
pub struct BallJoint {
/// Whether angular limits are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub limits_enabled: bool,
/// Allowed angles range for the joint (in radians).
#[visit(optional)] // Backward compatibility
pub limits_angles: Range<f32>,
}
@@ -85,11 +83,9 @@ pub struct FixedJoint;
#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
pub struct PrismaticJoint {
/// Whether linear limits along local X axis of the joint are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub limits_enabled: bool,
/// Allowed linear distance range along local X axis of the joint.
#[visit(optional)] // Backward compatibility
pub limits: Range<f32>,
}
@@ -177,7 +173,6 @@ pub struct Joint {
pub(crate) params: InheritableVariable<JointParams>,
#[reflect(setter = "set_motor_params")]
#[visit(optional)] // Backward compatibility
pub(crate) motor_params: InheritableVariable<JointMotorParams>,
#[reflect(setter = "set_body1")]
@@ -186,7 +181,6 @@ pub struct Joint {
#[reflect(setter = "set_body2")]
pub(crate) body2: InheritableVariable<Handle<RigidBody>>,
#[visit(optional)] // Backward compatibility
#[reflect(setter = "set_contacts_enabled")]
pub(crate) contacts_enabled: InheritableVariable<bool>,
+2 -30
View File
@@ -37,7 +37,7 @@ use crate::{
visitor::prelude::*,
},
graph::{constructor::ConstructorProvider, BaseSceneGraph},
material::{self, Material, MaterialResource},
material::{Material, MaterialResource},
renderer::{self, bundle::RenderContext},
scene::{
base::{Base, BaseBuilder},
@@ -170,7 +170,7 @@ impl Hash for RectangleVertex {
/// image, but just changing portion for rendering. Keep in mind that the coordinates are normalized
/// which means `[0; 0]` corresponds to top-left corner of the texture and `[1; 1]` corresponds to
/// right-bottom corner.
#[derive(Reflect, Debug, Clone, ComponentProvider)]
#[derive(Reflect, Debug, Clone, Visit, ComponentProvider)]
#[reflect(derived_type = "Node")]
pub struct Rectangle {
base: Base,
@@ -190,34 +190,6 @@ pub struct Rectangle {
flip_y: InheritableVariable<bool>,
}
impl Visit for Rectangle {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
if region.is_reading() {
if let Some(material) =
material::visit_old_texture_as_material(&mut region, Material::standard_2d)
{
self.material = material.into();
} else {
self.material.visit("Material", &mut region)?;
}
} else {
self.material.visit("Material", &mut region)?;
}
self.base.visit("Base", &mut region)?;
self.color.visit("Color", &mut region)?;
// Backward compatibility.
let _ = self.flip_x.visit("FlipX", &mut region);
let _ = self.flip_y.visit("FlipY", &mut region);
let _ = self.uv_rect.visit("UvRect", &mut region);
Ok(())
}
}
impl Default for Rectangle {
fn default() -> Self {
Self {
+2 -6
View File
@@ -1742,7 +1742,7 @@ impl Visit for Graph {
self.sound_context.visit("SoundContext", &mut region)?;
self.physics.visit("PhysicsWorld", &mut region)?;
self.physics2d.visit("PhysicsWorld2D", &mut region)?;
let _ = self.lightmap.visit("Lightmap", &mut region);
self.lightmap.visit("Lightmap", &mut region)?;
Ok(())
}
@@ -1975,7 +1975,6 @@ mod test {
script::ScriptTrait,
};
use fyrox_core::algebra::Vector2;
use fyrox_core::append_extension;
use fyrox_resource::untyped::ResourceKind;
use std::{fs, path::Path, sync::Arc};
@@ -2184,10 +2183,7 @@ mod test {
fn save_scene(scene: &mut Scene, path: &Path) {
let mut visitor = Visitor::new();
scene.save("Scene", &mut visitor).unwrap();
visitor.save_binary_to_file(path).unwrap();
visitor
.save_ascii_to_file(append_extension(path, "txt"))
.unwrap();
visitor.save_ascii_to_file(path).unwrap();
}
fn make_resource_manager(root: &Path) -> ResourceManager {
+1 -14
View File
@@ -60,27 +60,21 @@ use strum_macros::{AsRefStr, EnumString, VariantNames};
#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
pub struct BallJoint {
/// Whether X angular limits are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub x_limits_enabled: bool,
/// Allowed angle range around local X axis of the joint (in radians).
#[visit(optional)] // Backward compatibility
pub x_limits_angles: Range<f32>,
/// Whether Y angular limits are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub y_limits_enabled: bool,
/// Allowed angle range around local Y axis of the joint (in radians).
#[visit(optional)] // Backward compatibility
pub y_limits_angles: Range<f32>,
/// Whether Z angular limits are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub z_limits_enabled: bool,
/// Allowed angle range around local Z axis of the joint (in radians).
#[visit(optional)] // Backward compatibility
pub z_limits_angles: Range<f32>,
}
@@ -107,11 +101,9 @@ pub struct FixedJoint;
#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
pub struct PrismaticJoint {
/// Whether linear limits along local joint X axis are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub limits_enabled: bool,
/// The min an max relative position of the attached bodies along local X axis of the joint.
#[visit(optional)] // Backward compatibility
/// The min and max relative position of the attached bodies along local X axis of the joint.
pub limits: Range<f32>,
}
@@ -130,11 +122,9 @@ impl Default for PrismaticJoint {
#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
pub struct RevoluteJoint {
/// Whether angular limits around local X axis of the joint are enabled or not. Default is `false`
#[visit(optional)] // Backward compatibility
pub limits_enabled: bool,
/// Allowed angle range around local X axis of the joint (in radians).
#[visit(optional)] // Backward compatibility
pub limits: Range<f32>,
}
@@ -224,7 +214,6 @@ pub struct Joint {
pub(crate) params: InheritableVariable<JointParams>,
#[reflect(setter = "set_motor_params")]
#[visit(optional)] // Backward compatibility
pub(crate) motor_params: InheritableVariable<JointMotorParams>,
#[reflect(setter = "set_body1")]
@@ -234,11 +223,9 @@ pub struct Joint {
pub(crate) body2: InheritableVariable<Handle<RigidBody>>,
#[reflect(setter = "set_contacts_enabled")]
#[visit(optional)] // Backward compatibility
pub(crate) contacts_enabled: InheritableVariable<bool>,
#[reflect(setter = "set_auto_rebinding")]
#[visit(optional)] // Backward compatibility
pub(crate) auto_rebind: InheritableVariable<bool>,
#[visit(optional)]
+3 -25
View File
@@ -43,7 +43,7 @@ use crate::{
visitor::{Visit, VisitResult, Visitor},
Uuid,
},
material::{self, Material, MaterialResource, MaterialResourceExtension},
material::{Material, MaterialResource, MaterialResourceExtension},
resource::texture::{TextureKind, TexturePixelKind, TextureResource, TextureResourceExtension},
scene::{
mesh::{
@@ -1250,7 +1250,7 @@ impl SurfaceResourceExtension for SurfaceResource {
///
/// This code snippet creates a cone surface instance, check the docs for [`SurfaceData`] for more info about built-in
/// methods.
#[derive(Debug, Reflect, PartialEq)]
#[derive(Debug, Reflect, Visit, PartialEq)]
pub struct Surface {
pub(crate) data: InheritableVariable<SurfaceResource>,
@@ -1271,6 +1271,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.
#[reflect(hidden)]
#[visit(skip)]
pub(crate) vertex_weights: Vec<VertexWeightSet>,
}
@@ -1294,29 +1295,6 @@ impl Clone for Surface {
}
}
impl Visit for Surface {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
// Backward compatibility.
if region.is_reading() {
if let Some(material) = material::visit_old_material(&mut region) {
self.material = material.into();
} else {
self.material.visit("Material", &mut region)?;
}
} else {
self.material.visit("Material", &mut region)?;
}
self.data.visit("Data", &mut region)?;
self.bones.visit("Bones", &mut region)?;
let _ = self.unique_material.visit("UniqueMaterial", &mut region); // Backward compatibility.
Ok(())
}
}
impl Default for Surface {
fn default() -> Self {
Self {
+1 -115
View File
@@ -21,10 +21,7 @@
//! Contains most common vertex formats and their layouts.
use crate::{
core::{
algebra::{Vector2, Vector3, Vector4},
visitor::{Visit, VisitResult, Visitor},
},
core::algebra::{Vector2, Vector3, Vector4},
scene::mesh::buffer::{
VertexAttributeDataType, VertexAttributeDescriptor, VertexAttributeUsage, VertexTrait,
},
@@ -290,114 +287,3 @@ impl Hash for SimpleVertex {
}
}
}
/// Fat vertex used before customizable VertexBuffer was made.
/// It is used only to be able to load scenes in old formats to
/// keep backward compatibility.
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)] // OpenGL expects this structure packed as in C
pub struct OldVertex {
/// Position of vertex in local coordinates.
pub position: Vector3<f32>,
/// Texture coordinates.
pub tex_coord: Vector2<f32>,
/// Normal in local coordinates.
pub normal: Vector3<f32>,
/// Tangent vector in local coordinates.
pub tangent: Vector4<f32>,
/// Array of bone weights. Unused bones will have 0.0 weight so they won't
/// impact the shape of mesh.
pub bone_weights: [f32; 4],
/// Array of bone indices. It has indices of bones in array of bones of a
/// surface.
pub bone_indices: [u8; 4],
/// Second texture coordinates.
pub second_tex_coord: Vector2<f32>,
}
impl Visit for OldVertex {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
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", &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", &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)?;
Ok(())
}
}
impl VertexTrait for OldVertex {
fn layout() -> &'static [VertexAttributeDescriptor] {
&[
VertexAttributeDescriptor {
usage: VertexAttributeUsage::Position,
data_type: VertexAttributeDataType::F32,
size: 3,
divisor: 0,
shader_location: 0,
normalized: false,
},
VertexAttributeDescriptor {
usage: VertexAttributeUsage::TexCoord0,
data_type: VertexAttributeDataType::F32,
size: 2,
divisor: 0,
shader_location: 1,
normalized: false,
},
VertexAttributeDescriptor {
usage: VertexAttributeUsage::Normal,
data_type: VertexAttributeDataType::F32,
size: 3,
divisor: 0,
shader_location: 2,
normalized: false,
},
VertexAttributeDescriptor {
usage: VertexAttributeUsage::Tangent,
data_type: VertexAttributeDataType::F32,
size: 4,
divisor: 0,
shader_location: 3,
normalized: false,
},
VertexAttributeDescriptor {
usage: VertexAttributeUsage::BoneWeight,
data_type: VertexAttributeDataType::F32,
size: 4,
divisor: 0,
shader_location: 4,
normalized: false,
},
VertexAttributeDescriptor {
usage: VertexAttributeUsage::BoneIndices,
data_type: VertexAttributeDataType::U8,
size: 4,
divisor: 0,
shader_location: 5,
normalized: false,
},
VertexAttributeDescriptor {
usage: VertexAttributeUsage::TexCoord1,
data_type: VertexAttributeDataType::F32,
size: 2,
divisor: 0,
shader_location: 6,
normalized: false,
},
]
}
}
+3 -20
View File
@@ -69,10 +69,8 @@ use crate::{
graphics::PolygonFillMode,
resource::texture::TextureResource,
scene::{
base::BaseBuilder,
debug::SceneDrawingContext,
graph::{Graph, GraphPerformanceStatistics, GraphUpdateSwitches},
navmesh::NavigationalMeshBuilder,
node::Node,
skybox::{SkyBox, SkyBoxKind},
sound::SoundEngine,
@@ -569,24 +567,9 @@ impl Scene {
self.graph.visit("Graph", &mut region)?;
self.enabled.visit("Enabled", &mut region)?;
let _ = self
.rendering_options
.visit("RenderingOptions", &mut region);
let _ = self.sky_box.visit("SkyBox", &mut region);
// Backward compatibility.
if region.is_reading() {
let mut navmeshes = NavMeshContainer::default();
if navmeshes.visit("NavMeshes", &mut region).is_ok() {
for (i, navmesh) in navmeshes.iter().enumerate() {
NavigationalMeshBuilder::new(
BaseBuilder::new().with_name(format!("Navmesh{i}")),
)
.with_navmesh(navmesh.clone())
.build(&mut self.graph);
}
}
}
self.rendering_options
.visit("RenderingOptions", &mut region)?;
self.sky_box.visit("SkyBox", &mut region)?;
Ok(())
}
+1 -1
View File
@@ -751,7 +751,7 @@ mod test {
fn save_scene(scene: &mut Scene, path: &Path) {
let mut visitor = Visitor::new();
scene.save("Scene", &mut visitor).unwrap();
visitor.save_binary_to_file(path).unwrap();
visitor.save_ascii_to_file(path).unwrap();
}
#[test]
@@ -39,7 +39,6 @@ pub struct BaseEmitter {
#[visit(rename = "SpawnRate")]
particle_spawn_rate: u32,
/// Maximum amount of particles emitter can emit. Unlimited if < 0
#[visit(optional)] // Backward compatibility
max_particles: Option<u32>,
/// Range of initial lifetime of a particle
#[visit(rename = "LifeTime")]
+8 -32
View File
@@ -36,7 +36,7 @@ use crate::{
variable::InheritableVariable,
visitor::prelude::*,
},
material::{self, Material, MaterialResource},
material::{Material, MaterialResource},
rand::{prelude::StdRng, RngCore, SeedableRng},
renderer::{self, bundle::RenderContext},
scene::{
@@ -309,37 +309,13 @@ impl Visit for ParticleSystem {
self.is_playing.visit("Enabled", &mut region)?;
self.particles.visit("Particles", &mut region)?;
self.free_particles.visit("FreeParticles", &mut region)?;
let _ = self.rng.visit("Rng", &mut region);
let _ = self.visible_distance.visit("VisibleDistance", &mut region);
let _ = self
.coordinate_system
.visit("CoordinateSystem", &mut region);
let _ = self.fadeout_margin.visit("FadeoutMargin", &mut region);
// Backward compatibility.
if region.is_reading() {
if let Some(material) = material::visit_old_texture_as_material(
&mut region,
Material::standard_particle_system,
) {
self.material = material.into();
} else {
self.material.visit("Material", &mut region)?;
}
} else {
self.material.visit("Material", &mut region)?;
}
let mut soft_boundary_sharpness_factor = 100.0;
if soft_boundary_sharpness_factor
.visit("SoftBoundarySharpnessFactor", &mut region)
.is_ok()
{
self.material.data_ref().set_property(
"softBoundarySharpnessFactor",
soft_boundary_sharpness_factor,
);
}
self.rng.visit("Rng", &mut region)?;
self.visible_distance
.visit("VisibleDistance", &mut region)?;
self.coordinate_system
.visit("CoordinateSystem", &mut region)?;
self.fadeout_margin.visit("FadeoutMargin", &mut region)?;
self.material.visit("Material", &mut region)?;
Ok(())
}
+2 -32
View File
@@ -36,7 +36,7 @@ use crate::{
visitor::{Visit, VisitResult, Visitor},
},
graph::{constructor::ConstructorProvider, BaseSceneGraph},
material::{self, Material, MaterialResource},
material::{Material, MaterialResource},
renderer::{self, bundle::RenderContext},
scene::{
base::{Base, BaseBuilder},
@@ -152,7 +152,7 @@ impl VertexTrait for SpriteVertex {
/// **does not** reuse it. Ideally, you should reuse the shared material across multiple instances
/// to get the best possible performance. Otherwise, each your sprite will be put in a separate batch
/// which will force your GPU to render a single sprite in dedicated draw call which is quite slow.
#[derive(Debug, Reflect, Clone, ComponentProvider)]
#[derive(Debug, Reflect, Clone, ComponentProvider, Visit)]
#[reflect(derived_type = "Node")]
pub struct Sprite {
base: Base,
@@ -179,36 +179,6 @@ pub struct Sprite {
flip_y: InheritableVariable<bool>,
}
impl Visit for Sprite {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
if region.is_reading() {
if let Some(material) =
material::visit_old_texture_as_material(&mut region, Material::standard_sprite)
{
self.material = material.into();
} else {
self.material.visit("Material", &mut region)?;
}
} else {
self.material.visit("Material", &mut region)?;
}
self.base.visit("Base", &mut region)?;
self.color.visit("Color", &mut region)?;
self.size.visit("Size", &mut region)?;
self.rotation.visit("Rotation", &mut region)?;
// Backward compatibility.
let _ = self.flip_x.visit("FlipX", &mut region);
let _ = self.flip_y.visit("FlipY", &mut region);
let _ = self.uv_rect.visit("UvRect", &mut region);
Ok(())
}
}
impl Deref for Sprite {
type Target = Base;
+28 -187
View File
@@ -79,13 +79,12 @@ mod quadtree;
use crate::scene::node::constructor::NodeConstructor;
pub use brushstroke::*;
use fyrox_core::visitor::pod::PodVecView;
use fyrox_graph::constructor::ConstructorProvider;
use super::collider::BitMask;
/// Current implementation version marker.
pub const VERSION: u8 = 2;
pub const VERSION: u8 = 0;
lazy_static! {
/// Solid white texture
@@ -418,58 +417,22 @@ impl Visit for Chunk {
let mut region = visitor.enter_region(name)?;
let mut version = VERSION;
let _ = version.visit("Version", &mut region);
version.visit("Version", &mut region)?;
match version {
0 => {
let mut height_map = Vec::<f32>::new();
let mut view = PodVecView::from_pod_vec(&mut height_map);
view.visit("Heightmap", &mut region)?;
self.position.visit("Position", &mut region)?;
let mut width = 0.0f32;
width.visit("Width", &mut region)?;
let mut length = 0.0f32;
length.visit("Length", &mut region)?;
self.physical_size = Vector2::new(width, length);
let mut width_point_count = 0u32;
width_point_count.visit("WidthPointCount", &mut region)?;
let mut length_point_count = 0u32;
length_point_count.visit("LengthPointCount", &mut region)?;
self.height_map_size = Vector2::new(width_point_count, length_point_count);
self.grid_position = Vector2::new(
(self.position.x / width) as i32,
(self.position.y / length) as i32,
);
self.heightmap = Some(make_height_map_texture(
height_map,
Vector2::new(width_point_count, length_point_count),
));
if let VERSION = version {
self.heightmap.visit("Heightmap", &mut region)?;
self.hole_mask.visit("HoleMask", &mut region)?;
// We do not need to visit position, since its value is implied by grid_position.
//self.position.visit("Position", &mut region)?;
self.physical_size.visit("PhysicalSize", &mut region)?;
self.height_map_size.visit("HeightMapSize", &mut region)?;
self.layer_masks.visit("LayerMasks", &mut region)?;
self.grid_position.visit("GridPosition", &mut region)?;
// Set position to have the value implied by grid_position
if region.is_reading() {
self.position = self.position()
}
1 | VERSION => {
self.heightmap.visit("Heightmap", &mut region)?;
let _ = self.hole_mask.visit("HoleMask", &mut region);
// We do not need to visit position, since its value is implied by grid_position.
//self.position.visit("Position", &mut region)?;
self.physical_size.visit("PhysicalSize", &mut region)?;
self.height_map_size.visit("HeightMapSize", &mut region)?;
self.layer_masks.visit("LayerMasks", &mut region)?;
self.grid_position.visit("GridPosition", &mut region)?;
// Set position to have the value implied by grid_position
if region.is_reading() {
self.position = self.position()
}
let _ = self.block_size.visit("BlockSize", &mut region);
}
_ => (),
}
if region.is_reading() && version < 2 {
self.create_margin();
self.block_size.visit("BlockSize", &mut region)?;
}
self.quad_tree = Mutex::new(make_quad_tree(
@@ -1151,151 +1114,29 @@ impl Default for Terrain {
}
}
#[derive(Visit)]
struct OldLayer {
pub material: MaterialResource,
pub mask_property_name: String,
pub chunk_masks: Vec<TextureResource>,
}
impl Default for OldLayer {
fn default() -> Self {
Self {
material: MaterialResource::new_ok(
Uuid::new_v4(),
Default::default(),
Material::standard_terrain(),
),
mask_property_name: "maskTexture".to_string(),
chunk_masks: Default::default(),
}
}
}
impl Visit for Terrain {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
let mut version = VERSION;
let _ = version.visit("Version", &mut region);
version.visit("Version", &mut region)?;
match version {
0 => {
// Old version.
self.base.visit("Base", &mut region)?;
let mut layers =
InheritableVariable::<Vec<OldLayer>>::new_modified(Default::default());
layers.visit("Layers", &mut region)?;
let mut width = 0.0f32;
width.visit("Width", &mut region)?;
let mut length = 0.0f32;
length.visit("Length", &mut region)?;
let mut mask_resolution = 0.0f32;
mask_resolution.visit("MaskResolution", &mut region)?;
let mut height_map_resolution = 0.0f32;
height_map_resolution.visit("HeightMapResolution", &mut region)?;
let mut chunks = Vec::<Chunk>::new();
chunks.visit("Chunks", &mut region)?;
let mut width_chunks = 0u32;
width_chunks.visit("WidthChunks", &mut region)?;
self.width_chunks = (0..(width_chunks as i32)).into();
let mut length_chunks = 0u32;
length_chunks.visit("LengthChunks", &mut region)?;
self.length_chunks = (0..(length_chunks as i32)).into();
self.chunk_size =
Vector2::new(width / width_chunks as f32, length / length_chunks as f32).into();
self.mask_size = Vector2::new(
(self.chunk_size.x * mask_resolution) as u32,
(self.chunk_size.y * mask_resolution) as u32,
)
.into();
self.height_map_size = Vector2::new(
(self.chunk_size.x * height_map_resolution) as u32,
(self.chunk_size.y * height_map_resolution) as u32,
)
.into();
// Convert to new format.
for mut layer in layers.take() {
for chunk in chunks.iter_mut().rev() {
chunk.layer_masks.push(layer.chunk_masks.pop().unwrap());
}
// TODO: Due to the bug in resource system, material properties are not kept in sync
// so here we must re-create the material and put every property from the old material
// to the new.
let new_material = Material::standard_terrain();
// TODO
/*
let mut material_state = layer.material.state();
if let Some(material) = material_state.data() {
for (name, value) in material.properties() {
Log::verify(new_material.set_property(name.clone(), value.clone()));
}
}*/
self.layers.push(Layer {
material: MaterialResource::new_ok(
Uuid::new_v4(),
Default::default(),
new_material,
),
mask_property_name: layer.mask_property_name,
..Default::default()
});
}
self.chunks = chunks.into();
}
1 | VERSION => {
// Current version
self.base.visit("Base", &mut region)?;
let _ = self.holes_enabled.visit("HolesEnabled", &mut region);
self.layers.visit("Layers", &mut region)?;
self.chunk_size.visit("ChunkSize", &mut region)?;
self.width_chunks.visit("WidthChunks", &mut region)?;
self.length_chunks.visit("LengthChunks", &mut region)?;
self.height_map_size.visit("HeightMapSize", &mut region)?;
let _ = self.block_size.visit("BlockSize", &mut region);
self.mask_size.visit("MaskSize", &mut region)?;
self.chunks.visit("Chunks", &mut region)?;
}
_ => (),
if let VERSION = version {
// Current version
self.base.visit("Base", &mut region)?;
self.holes_enabled.visit("HolesEnabled", &mut region)?;
self.layers.visit("Layers", &mut region)?;
self.chunk_size.visit("ChunkSize", &mut region)?;
self.width_chunks.visit("WidthChunks", &mut region)?;
self.length_chunks.visit("LengthChunks", &mut region)?;
self.height_map_size.visit("HeightMapSize", &mut region)?;
self.block_size.visit("BlockSize", &mut region)?;
self.mask_size.visit("MaskSize", &mut region)?;
self.chunks.visit("Chunks", &mut region)?;
}
if region.is_reading() {
self.geometry = TerrainGeometry::new(*self.block_size);
if version < 2 {
Log::info(format!("Updating terrain to version: {VERSION}"));
*self.height_map_size = self.height_map_size.map(|x| x + 2);
for c in self.chunks.iter() {
if c.height_map_size() != self.height_map_size() {
Log::err(format!(
"Terrain version update failure, height map size mismatch: {} != {}",
c.height_map_size(),
self.height_map_size()
));
}
}
for pos in self
.chunks
.iter()
.map(|c| c.grid_position)
.collect::<Vec<_>>()
{
self.align_chunk_margins(pos);
}
}
}
Ok(())
+2 -17
View File
@@ -92,7 +92,7 @@ use std::{
};
/// Current implementation version marker.
pub const VERSION: u8 = 1;
pub const VERSION: u8 = 0;
lazy_static! {
/// The default material for tiles that have no material set.
@@ -979,27 +979,12 @@ impl Visit for TileMap {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
let mut version = if region.is_reading() { 0 } else { VERSION };
let _ = version.visit("Version", &mut region);
version.visit("Version", &mut region)?;
self.base.visit("Base", &mut region)?;
self.tile_set.visit("TileSet", &mut region)?;
self.tile_scale.visit("TileScale", &mut region)?;
self.active_brush.visit("ActiveBrush", &mut region)?;
match version {
0 => {
let mut tiles = InheritableVariable::new_non_modified(Tiles::default());
let result = tiles.visit("Tiles", &mut region);
result?;
let mut data = TileMapData::default();
for (p, h) in tiles.iter() {
data.set(*p, *h);
}
self.tiles = Some(Resource::new_ok(
Uuid::new_v4(),
ResourceKind::Embedded,
data,
))
.into();
}
VERSION => {
self.tiles.visit("Tiles", &mut region)?;
}
+2 -17
View File
@@ -38,7 +38,7 @@ use crate::{
Mesh,
},
utils::{
astar::{Graph, GraphVertex, PathError, PathKind, VertexData, VertexDataProvider},
astar::{Graph, PathError, PathKind, VertexData, VertexDataProvider},
raw_mesh::{RawMeshBuilder, RawVertex},
},
};
@@ -94,22 +94,7 @@ impl Visit for Navmesh {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
// Backward compatibility.
if region.is_reading() {
let mut pathfinder = Graph::<GraphVertex>::new();
if pathfinder.visit("PathFinder", &mut region).is_ok() {
self.vertices = pathfinder
.vertices
.iter()
.map(|v| v.position)
.collect::<Vec<_>>();
} else {
self.vertices.visit("Vertices", &mut region)?;
}
} else {
self.vertices.visit("Vertices", &mut region)?;
}
self.vertices.visit("Vertices", &mut region)?;
self.triangles.visit("Triangles", &mut region)?;
drop(region);
+4 -126
View File
@@ -10,14 +10,12 @@ use fyrox_core::{
algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
color::Color,
io::FileError,
parking_lot::Mutex,
reflect::prelude::*,
sstorage::ImmutableString,
uuid::{uuid, Uuid},
visitor::{prelude::*, RegionGuard},
SafeLock, TypeUuidProvider,
visitor::prelude::*,
TypeUuidProvider,
};
use fyrox_graphics::gpu_program::SamplerFallback;
use fyrox_resource::{
io::ResourceIo,
manager::{BuiltInResource, ResourceManager},
@@ -609,40 +607,6 @@ pub struct Material {
resource_bindings: FxHashMap<ImmutableString, MaterialResourceBinding>,
}
#[derive(Debug, Visit, Clone, Reflect)]
enum OldMaterialProperty {
Float(f32),
FloatArray(Vec<f32>),
Int(i32),
IntArray(Vec<i32>),
UInt(u32),
UIntArray(Vec<u32>),
Vector2(Vector2<f32>),
Vector2Array(Vec<Vector2<f32>>),
Vector3(Vector3<f32>),
Vector3Array(Vec<Vector3<f32>>),
Vector4(Vector4<f32>),
Vector4Array(Vec<Vector4<f32>>),
Matrix2(Matrix2<f32>),
Matrix2Array(Vec<Matrix2<f32>>),
Matrix3(Matrix3<f32>),
Matrix3Array(Vec<Matrix3<f32>>),
Matrix4(Matrix4<f32>),
Matrix4Array(Vec<Matrix4<f32>>),
Bool(bool),
Color(Color),
Sampler {
value: Option<TextureResource>,
fallback: SamplerFallback,
},
}
impl Default for OldMaterialProperty {
fn default() -> Self {
Self::Float(0.0)
}
}
impl Visit for Material {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
@@ -659,56 +623,8 @@ impl Visit for Material {
shader.visit("Shader", &mut region)?;
self.shader = shader;
if region.is_reading() {
// Backward compatibility.
let mut old_properties = FxHashMap::<ImmutableString, OldMaterialProperty>::default();
if old_properties.visit("Properties", &mut region).is_ok() {
for (name, old_property) in &old_properties {
if let OldMaterialProperty::Sampler { value, .. } = old_property {
self.bind(
name.clone(),
MaterialResourceBinding::Texture(MaterialTextureBinding {
value: value.clone(),
}),
)
}
}
let properties = self.try_get_or_insert_property_group("properties");
for (name, old_property) in old_properties {
match old_property {
OldMaterialProperty::Float(v) => properties.set_property(name, v),
OldMaterialProperty::FloatArray(v) => properties.set_property(name, v),
OldMaterialProperty::Int(v) => properties.set_property(name, v),
OldMaterialProperty::IntArray(v) => properties.set_property(name, v),
OldMaterialProperty::UInt(v) => properties.set_property(name, v),
OldMaterialProperty::UIntArray(v) => properties.set_property(name, v),
OldMaterialProperty::Vector2(v) => properties.set_property(name, v),
OldMaterialProperty::Vector2Array(v) => properties.set_property(name, v),
OldMaterialProperty::Vector3(v) => properties.set_property(name, v),
OldMaterialProperty::Vector3Array(v) => properties.set_property(name, v),
OldMaterialProperty::Vector4(v) => properties.set_property(name, v),
OldMaterialProperty::Vector4Array(v) => properties.set_property(name, v),
OldMaterialProperty::Matrix2(v) => properties.set_property(name, v),
OldMaterialProperty::Matrix2Array(v) => properties.set_property(name, v),
OldMaterialProperty::Matrix3(v) => properties.set_property(name, v),
OldMaterialProperty::Matrix3Array(v) => properties.set_property(name, v),
OldMaterialProperty::Matrix4(v) => properties.set_property(name, v),
OldMaterialProperty::Matrix4Array(v) => properties.set_property(name, v),
OldMaterialProperty::Bool(v) => properties.set_property(name, v),
OldMaterialProperty::Color(v) => properties.set_property(name, v),
_ => (),
};
}
} else {
self.resource_bindings
.visit("ResourceBindings", &mut region)?;
}
} else {
self.resource_bindings
.visit("ResourceBindings", &mut region)?;
}
self.resource_bindings
.visit("ResourceBindings", &mut region)?;
Ok(())
}
@@ -1168,44 +1084,6 @@ impl MaterialResourceExtension for MaterialResource {
}
}
#[doc(hidden)]
pub fn visit_old_material(region: &mut RegionGuard) -> Option<MaterialResource> {
let mut old_material = Arc::new(Mutex::new(Material::default()));
if let Ok(mut inner) = region.enter_region("Material") {
if old_material.visit("Value", &mut inner).is_ok() {
return Some(MaterialResource::new_ok(
Uuid::new_v4(),
Default::default(),
old_material.safe_lock().clone(),
));
}
}
None
}
#[doc(hidden)]
pub fn visit_old_texture_as_material<F>(
region: &mut RegionGuard,
make_default_material: F,
) -> Option<MaterialResource>
where
F: FnOnce() -> Material,
{
let mut old_texture: Option<TextureResource> = None;
if let Ok(mut inner) = region.enter_region("Texture") {
if old_texture.visit("Value", &mut inner).is_ok() {
let mut material = make_default_material();
material.bind("diffuseTexture", old_texture);
return Some(MaterialResource::new_ok(
Uuid::new_v4(),
Default::default(),
material,
));
}
}
None
}
lazy_static! {
/// Standard PBR material. Keep in mind that this material is global, any modification
/// of it will reflect on every other usage of it.
+2 -2
View File
@@ -467,7 +467,7 @@ pub use fyrox_graphics::gpu_program::{
use fyrox_graphics::{gpu_program::ShaderProperty, DrawParameters};
use fyrox_resource::{
embedded_data_source, io::ResourceIo, manager::BuiltInResource, untyped::ResourceKind,
Resource, ResourceData, SHADER_RESOURCE_UUID,
Resource, ResourceData,
};
use lazy_static::lazy_static;
use ron::ser::PrettyConfig;
@@ -528,7 +528,7 @@ pub struct Shader {
impl TypeUuidProvider for Shader {
fn type_uuid() -> Uuid {
SHADER_RESOURCE_UUID
uuid!("f1346417-b726-492a-b80f-c02096c6c019")
}
}
-15
View File
@@ -69,21 +69,6 @@ pub mod registry;
pub mod state;
pub mod untyped;
/// Type UUID of texture resource. It is defined here to load old versions of resources.
pub const TEXTURE_RESOURCE_UUID: Uuid = uuid!("02c23a44-55fa-411a-bc39-eb7a5eadf15c");
/// Type UUID of model resource. It is defined here to load old versions of resources.
pub const MODEL_RESOURCE_UUID: Uuid = uuid!("44cd768f-b4ca-4804-a98c-0adf85577ada");
/// Type UUID of sound buffer resource. It is defined here to load old versions of resources.
pub const SOUND_BUFFER_RESOURCE_UUID: Uuid = uuid!("f6a077b7-c8ff-4473-a95b-0289441ea9d8");
/// Type UUID of shader resource. It is defined here to load old versions of resources.
pub const SHADER_RESOURCE_UUID: Uuid = uuid!("f1346417-b726-492a-b80f-c02096c6c019");
/// Type UUID of curve resource. It is defined here to load old versions of resources.
pub const CURVE_RESOURCE_UUID: Uuid = uuid!("f28b949f-28a2-4b68-9089-59c234f58b6b");
/// Type UUID of HRIR sphere resource. It is defined here to load old versions of resources.
pub const HRIR_SPHERE_RESOURCE_UUID: Uuid = uuid!("c92a0fa3-0ed3-49a9-be44-8f06271c6be2");
/// Type UUID of font resource. It is defined here to load old versions of resources.
pub const FONT_RESOURCE_UUID: Uuid = uuid!("692fec79-103a-483c-bb0b-9fc3a349cb48");
/// A trait for resource data.
pub trait ResourceData: Debug + Visit + Send + Reflect {
/// Returns unique data type id.
+7 -261
View File
@@ -21,19 +21,17 @@
//! A module for untyped resources. See [`UntypedResource`] docs for more info.
use crate::state::ResourceDataWrapper;
use crate::ResourceHeaderGuard;
use crate::{
core::{
math::curve::Curve, parking_lot::Mutex, reflect::prelude::*, uuid, uuid::Uuid,
visitor::prelude::*, TypeUuidProvider,
parking_lot::Mutex, reflect::prelude::*, uuid, uuid::Uuid, visitor::prelude::*,
TypeUuidProvider,
},
manager::ResourceManager,
state::{LoadError, ResourceState},
Resource, ResourceData, ResourceLoadError, TypedResourceData, CURVE_RESOURCE_UUID,
MODEL_RESOURCE_UUID, SHADER_RESOURCE_UUID, SOUND_BUFFER_RESOURCE_UUID, TEXTURE_RESOURCE_UUID,
Resource, ResourceData, ResourceLoadError, TypedResourceData,
};
use crate::{ResourceHeaderGuard, FONT_RESOURCE_UUID, HRIR_SPHERE_RESOURCE_UUID};
use fxhash::FxHasher64;
use fyrox_core::io::FileError;
use fyrox_core::log::Log;
use fyrox_core::parking_lot::MutexGuard;
use fyrox_core::SafeLock;
@@ -41,7 +39,6 @@ use serde::{Deserialize, Serialize};
use std::fmt::Write;
use std::{
error::Error,
ffi::OsStr,
fmt::{Debug, Display, Formatter},
future::Future,
hash::{Hash, Hasher},
@@ -55,201 +52,6 @@ use std::{
const MISSING_RESOURCE_MANAGER: &str =
"Resource data constructor container must be provided when serializing resources!";
/// The UUIDs for resources that cannot be visited as embedded data because none of their
/// fields are visited. This is used by `LegacyHeader` to avoid mistakenly interpretting
/// a visitor node as an embedded resource.
/// Being on this list does *not* prevent future versions of these resources from being
/// embedded. It is purely a heuristic to assist with reading legacy resources.
const INVALID_EMBEDDED_RESOURCES: &[Uuid] = &[
SOUND_BUFFER_RESOURCE_UUID,
MODEL_RESOURCE_UUID,
HRIR_SPHERE_RESOURCE_UUID,
FONT_RESOURCE_UUID,
];
#[derive(Default, Debug, Visit, Clone, PartialEq, Eq, Hash)]
enum OldResourceKind {
#[default]
Embedded,
External(PathBuf),
}
#[derive(Debug)]
enum LegacyHeader {
Path(PathBuf),
Uuid(Uuid),
Data(Box<dyn ResourceData>),
}
impl LegacyHeader {
fn visit_path(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut path = PathBuf::default();
path.visit(name, visitor)?;
if path.as_os_str().is_empty() {
return Err(VisitError::FileLoadError(FileError::Custom(
"Empty path".to_string(),
)));
}
*self = Self::Path(path);
Ok(())
}
fn visit_details(&mut self, type_uuid: Uuid, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region("Details")?;
if type_uuid == SOUND_BUFFER_RESOURCE_UUID {
let mut sound_region = region.enter_region("0")?;
self.visit_path("Path", &mut sound_region)
} else {
self.visit_path("Path", &mut region)
}
}
fn take_data(&mut self, uuid: Uuid) -> Option<Box<dyn ResourceData>> {
if let Self::Data(data) = std::mem::replace(self, Self::Uuid(uuid)) {
Some(data)
} else {
None
}
}
fn is_valid_embedded_type_uuid(uuid: Uuid) -> bool {
INVALID_EMBEDDED_RESOURCES.contains(&uuid)
}
}
impl Default for LegacyHeader {
fn default() -> Self {
Self::Path(PathBuf::default())
}
}
impl Visit for LegacyHeader {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
assert!(visitor.is_reading());
let mut region = visitor.enter_region(name)?;
let mut type_uuid = Uuid::default();
if type_uuid.visit("TypeUuid", &mut region).is_err() {
// We might be reading the old version, try to guess an actual type uuid by
// the inner content of the resource data.
type_uuid = guess_uuid(&mut region);
};
let resource_manager = region
.blackboard
.get::<ResourceManager>()
.expect(MISSING_RESOURCE_MANAGER);
let resource_manager_state = resource_manager.state();
let Some(mut instance) = resource_manager_state
.constructors_container
.try_create(&type_uuid)
else {
return Err(VisitError::User(format!(
"There's no constructor registered for type {type_uuid}!"
)));
};
drop(resource_manager_state);
let mut id: u32 = 0;
if id.visit("Id", &mut region).is_ok() {
// We're interested only in embedded resources.
if id == 2 {
let result = self.visit_details(type_uuid, &mut region);
if let Err(err0) = result {
if Self::is_valid_embedded_type_uuid(type_uuid) {
let result = instance.visit("Details", &mut region);
if let Err(err1) = result {
let result = instance.visit("State", &mut region);
if let Err(err2) = result {
return Err(err0.multiple(err1).multiple(err2));
}
}
*self = Self::Data(instance);
Ok(())
} else {
Err(err0)
}
} else {
result
}
} else {
Err(VisitError::User("Old resource".into()))
}
} else {
let mut uuid = Uuid::default();
if uuid.visit("ResourceUuid", &mut region).is_ok() && !uuid.is_nil() {
*self = Self::Uuid(uuid);
return Ok(());
}
let mut old_kind = OldResourceKind::Embedded;
old_kind.visit("Kind", &mut region)?;
match old_kind {
OldResourceKind::External(path) => {
if path.as_os_str().is_empty() {
return Err(VisitError::FileLoadError(FileError::Custom(
"Empty path".to_string(),
)));
}
*self = Self::Path(path);
}
OldResourceKind::Embedded => {
instance.visit("State", &mut region)?;
*self = Self::Data(instance);
}
}
Ok(())
}
}
}
// Heuristic function to guess resource uuid based on inner content of a resource.
fn guess_uuid(region: &mut Visitor) -> Uuid {
assert!(region.is_reading());
let guard = region.enter_region("Details");
let mut region = match guard {
Ok(region) => region,
Err(ref err) => {
Log::err(err.to_string());
drop(guard);
Log::info(region.debug());
return TEXTURE_RESOURCE_UUID;
}
};
let mut mip_count = 0u32;
if mip_count.visit("MipCount", &mut region).is_ok() {
return TEXTURE_RESOURCE_UUID;
}
let mut curve = Curve::default();
if curve.visit("Curve", &mut region).is_ok() {
return CURVE_RESOURCE_UUID;
}
let mut id = 0u32;
if id.visit("Id", &mut region).is_ok() {
return SOUND_BUFFER_RESOURCE_UUID;
}
let mut path = PathBuf::new();
if path.visit("Path", &mut region).is_ok() {
let ext = path.extension().unwrap_or_default().to_ascii_lowercase();
if ext == OsStr::new("rgs")
|| ext == OsStr::new("fbx")
|| ext == OsStr::new("gltf")
|| ext == OsStr::new("glb")
{
return MODEL_RESOURCE_UUID;
} else if ext == OsStr::new("shader")
|| path == OsStr::new("Standard")
|| path == OsStr::new("StandardTwoSides")
|| path == OsStr::new("StandardTerrain")
{
return SHADER_RESOURCE_UUID;
}
}
Default::default()
}
/// Kind of a resource. It defines how the resource manager will treat a resource content on serialization.
#[derive(Default, Reflect, Debug, Visit, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ResourceKind {
@@ -537,16 +339,9 @@ impl UntypedResource {
let mut region = visitor.enter_region(name)?;
if region.is_reading() {
let mut uuid = Uuid::default();
match uuid.visit("Uuid", &mut region) {
Ok(()) => {
self.read_visit(uuid, type_uuid, &mut region)?;
drop(region);
}
Err(_) => {
drop(region);
self.legacy_visit(name, visitor)?;
}
}
uuid.visit("Uuid", &mut region)?;
self.read_visit(uuid, type_uuid, &mut region)?;
drop(region);
let resource_manager = visitor
.blackboard
.get::<ResourceManager>()
@@ -569,55 +364,6 @@ impl UntypedResource {
}
}
}
fn legacy_visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut header: Arc<Mutex<LegacyHeader>> = Default::default();
let result = header.visit(name, visitor);
if let Err(err1) = result {
header = Arc::default();
if let Ok(mut region) = visitor.enter_region(name) {
let mut region = if region.has_region("Value") {
region.enter_region("Value").unwrap()
} else {
region
};
let result = header.visit("State", &mut region);
if let Err(err2) = result {
if let Ok(mut region) = region.enter_region("State") {
let result = header.visit("Data", &mut region);
if let Err(err3) = result {
return Err(err1.multiple(err2).multiple(err3));
}
} else {
return Err(err1.multiple(err2));
}
}
} else {
return Err(err1);
}
}
let resource_manager = visitor
.blackboard
.get::<ResourceManager>()
.expect("Resource manager must be available when deserializing resources!")
.clone();
let mut state = resource_manager.state();
let mut header = header.try_lock().expect("header locked");
match *header {
LegacyHeader::Path(ref path) => {
Log::info(format!("Requesting {path:?}"));
*self = state.request(path);
}
LegacyHeader::Uuid(uuid) => {
*self = uuid.into();
}
LegacyHeader::Data(_) => {
let uuid = Uuid::new_v4();
let data = header.take_data(uuid).unwrap();
*self = UntypedResource::new_ok_untyped(uuid, ResourceKind::Embedded, data);
}
}
Ok(())
}
fn read_visit(
&mut self,
resource_uuid: Uuid,
+4 -4
View File
@@ -33,12 +33,12 @@ use crate::{
error::SoundError,
};
use fyrox_core::{
io::FileError, reflect::prelude::*, uuid::Uuid, visitor::prelude::*, TypeUuidProvider,
io::FileError, reflect::prelude::*, uuid, uuid::Uuid, visitor::prelude::*, TypeUuidProvider,
};
use fyrox_resource::untyped::ResourceKind;
use fyrox_resource::{
io::{FileReader, ResourceIo},
Resource, ResourceData, SOUND_BUFFER_RESOURCE_UUID,
Resource, ResourceData,
};
use std::{
error::Error,
@@ -298,7 +298,7 @@ impl SoundBufferResourceExtension for SoundBufferResource {
impl TypeUuidProvider for SoundBuffer {
fn type_uuid() -> Uuid {
SOUND_BUFFER_RESOURCE_UUID
uuid!("f6a077b7-c8ff-4473-a95b-0289441ea9d8")
}
}
@@ -348,7 +348,7 @@ impl DerefMut for SoundBuffer {
impl ResourceData for SoundBuffer {
fn type_uuid(&self) -> Uuid {
SOUND_BUFFER_RESOURCE_UUID
uuid!("f6a077b7-c8ff-4473-a95b-0289441ea9d8")
}
fn save(&mut self, _path: &Path) -> Result<(), Box<dyn Error>> {
+9 -10
View File
@@ -61,7 +61,7 @@ use fyrox_core::{
};
use fyrox_resource::{
embedded_data_source, io::ResourceIo, manager::BuiltInResource, options::ImportOptions,
untyped::ResourceKind, Resource, ResourceData, TEXTURE_RESOURCE_UUID,
untyped::ResourceKind, Resource, ResourceData,
};
use image::{ColorType, DynamicImage, ImageError, ImageFormat, Pixel};
use lazy_static::lazy_static;
@@ -287,7 +287,7 @@ pub struct Texture {
impl TypeUuidProvider for Texture {
fn type_uuid() -> Uuid {
TEXTURE_RESOURCE_UUID
uuid!("02c23a44-55fa-411a-bc39-eb7a5eadf15c")
}
}
@@ -363,17 +363,16 @@ impl Visit for Texture {
self.anisotropy.visit("Anisotropy", &mut region)?;
self.s_wrap_mode.visit("SWrapMode", &mut region)?;
self.t_wrap_mode.visit("TWrapMode", &mut region)?;
let _ = self.t_wrap_mode.visit("RWrapMode", &mut region);
self.t_wrap_mode.visit("RWrapMode", &mut region)?;
self.mip_count.visit("MipCount", &mut region)?;
self.kind.visit("Kind", &mut region)?;
let mut bytes_view = PodVecView::from_pod_vec(&mut self.bytes);
let _ = bytes_view.visit("Data", &mut region);
let _ = self.base_level.visit("BaseLevel", &mut region);
let _ = self.max_level.visit("MaxLevel", &mut region);
let _ = self.min_lod.visit("MinLod", &mut region);
let _ = self.max_lod.visit("MaxLod", &mut region);
let _ = self.lod_bias.visit("LodBias", &mut region);
bytes_view.visit("Data", &mut region)?;
self.base_level.visit("BaseLevel", &mut region)?;
self.max_level.visit("MaxLevel", &mut region)?;
self.min_lod.visit("MinLod", &mut region)?;
self.max_lod.visit("MaxLod", &mut region)?;
self.lod_bias.visit("LodBias", &mut region)?;
Ok(())
}
+5 -7
View File
@@ -816,13 +816,11 @@ impl Visit for UserInterface {
self.cursor_icon.visit("CursorIcon", &mut region)?;
self.double_click_time_slice
.visit("DoubleClickTimeSlice", &mut region)?;
let _ = self
.tooltip_appear_delay
.visit("TooltipAppearDelay", &mut region);
let _ = self
.standard_material
.visit("StandardMaterial", &mut region);
let _ = self.render_mode.visit("RenderMode", &mut region);
self.tooltip_appear_delay
.visit("TooltipAppearDelay", &mut region)?;
self.standard_material
.visit("StandardMaterial", &mut region)?;
self.render_mode.visit("RenderMode", &mut region)?;
if region.is_reading() {
for node in self.nodes.iter() {
-2
View File
@@ -276,10 +276,8 @@ pub struct Window {
pub prev_bounds: Option<Rect<f32>>,
/// If `true`, then the window can be closed using `Esc` key. Default is `true`. Works only if
/// `can_close` is also `true`.
#[visit(optional)] // Backward compatibility
pub close_by_esc: bool,
/// If `true`, then the window will be deleted after closing.
#[visit(optional)] // Backward compatibility
pub remove_on_close: bool,
}