Skip to content

Commit

Permalink
Improve serialization format of EffectAsset (#294)
Browse files Browse the repository at this point in the history
This change makes a few improvements to the serialized representation of
an `EffectAsset`:
- `LiteralExpr`, `ExprHandle`, and `Module` are now
  `#[serde(transparent)]`, which makes them less verbose.
- `VectorValue` is serialized as its glam math type representation,
  making it a lot more readable in text format (_e.g._ RON).

Before:

```
module: (
    expressions: [
        Literal((
            value: Vector((
                vector_type: (
                    elem_type: Float,
                    count: 3,
                ),
                storage: (1067030938, 3227307213, 1118770935, 0),
            )),
        )),
        Literal((
            value: Vector((
                vector_type: (
                    elem_type: Bool,
                    count: 2,
                ),
                storage: (0, 4294967295, 0, 0),
            )),
        )),
        Binary(
            op: Add,
            left: (
                index: 2,
            ),
            right: (
                index: 1,
            ),
        ),
    ],
),
```

After:

```
module: [
    Literal(Vector(Vec3((1.2, -3.45, 87.54485)))),
    Literal(Vector(BVec2((false, true)))),
    Binary(
        op: Add,
        left: 2,
        right: 1,
    ),
]
```
  • Loading branch information
djeedai authored Mar 3, 2024
1 parent 4fa610b commit 9d8d81f
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Merged the `InitModifier` and `UpdateModifier` traits into the `Modifier` subtrait; see other changelog entries for details. This helps manage modifiers in a unified way, and generally simplifies writing and maintain modifiers compatible with both the init and update contexts.
- `EffectAsset::init()` and `EffectAsset::update()` now take a `Modifier`-bound type, and validate its `ModifierContext` is compatible (and panics if not).
- `EffectAsset::render()` now panics if the modifier is not compatible with the `ModifierContext::Render`. Note that this indicates a malformed render modifier, because all objects implementing `RenderModifier` must include `ModifierContext::Render` in their `Modifier::context()`.
- Improved the serialization format to reduce verbosity, by making the following types `#[serde(transparent)]`: `ExprHandle`, `LiteralExpr`, `Module`.

### Removed

Expand Down
91 changes: 86 additions & 5 deletions src/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ impl AssetLoader for EffectAssetLoader {

#[cfg(test)]
mod tests {
use ron::ser::PrettyConfig;

use crate::*;

use super::*;
Expand Down Expand Up @@ -734,15 +736,94 @@ mod tests {

#[test]
fn test_serde_ron() {
let w = ExprWriter::new();

let pos = w.lit(Vec3::new(1.2, -3.45, 87.54485));
let x = w.lit(BVec2::new(false, true));
let _ = x + pos.clone();
let mod_pos = SetAttributeModifier::new(Attribute::POSITION, pos.expr());

let effect = EffectAsset {
name: "Effect".into(),
capacity: 4096,
spawner: Spawner::rate(30.0.into()),
module: w.finish(),
..Default::default()
};

let s = ron::to_string(&effect).unwrap();
let _effect_serde: EffectAsset = ron::from_str(&s).unwrap();
// assert_eq!(effect, effect_serde);
}
.with_property("my_prop", Vec3::new(1.2, -2.3, 55.32).into())
.init(mod_pos);

let s = ron::ser::to_string_pretty(&effect, PrettyConfig::new().new_line("\n".to_string()))
.unwrap();
assert_eq!(
s,
r#"(
name: "Effect",
capacity: 4096,
spawner: (
num_particles: Single(30.0),
spawn_time: Single(1.0),
period: Single(1.0),
starts_active: true,
starts_immediately: true,
),
z_layer_2d: 0.0,
simulation_space: Global,
simulation_condition: WhenVisible,
init_modifiers: [
{
"SetAttributeModifier": (
attribute: "position",
value: 1,
),
},
],
update_modifiers: [],
render_modifiers: [],
properties: [
(
name: "my_prop",
default_value: Vector(Vec3((1.2, -2.3, 55.32))),
),
],
motion_integration: PostUpdate,
module: [
Literal(Vector(Vec3((1.2, -3.45, 87.54485)))),
Literal(Vector(BVec2((false, true)))),
Binary(
op: Add,
left: 2,
right: 1,
),
],
alpha_mode: Blend,
)"#
);
let effect_serde: EffectAsset = ron::from_str(&s).unwrap();
assert_eq!(effect.name, effect_serde.name);
assert_eq!(effect.capacity, effect_serde.capacity);
assert_eq!(effect.spawner, effect_serde.spawner);
assert_eq!(effect.z_layer_2d, effect_serde.z_layer_2d);
assert_eq!(effect.simulation_space, effect_serde.simulation_space);
assert_eq!(
effect.simulation_condition,
effect_serde.simulation_condition
);
assert_eq!(effect.properties, effect_serde.properties);
assert_eq!(effect.motion_integration, effect_serde.motion_integration);
assert_eq!(effect.module, effect_serde.module);
assert_eq!(effect.alpha_mode, effect_serde.alpha_mode);
assert_eq!(
effect.init_modifiers().count(),
effect_serde.init_modifiers().count()
);
assert_eq!(
effect.update_modifiers().count(),
effect_serde.update_modifiers().count()
);
assert_eq!(
effect.render_modifiers().count(),
effect_serde.render_modifiers().count()
);
}
}
3 changes: 3 additions & 0 deletions src/graph/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ type Index = NonZeroU32;
Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
)]
#[repr(transparent)]
#[serde(transparent)]
pub struct ExprHandle {
index: Index,
}
Expand Down Expand Up @@ -161,6 +162,7 @@ impl ExprHandle {
/// [`lit()`]: Module::lit
/// [`attr()`]: Module::attr
#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Module {
expressions: Vec<Expr>,
}
Expand Down Expand Up @@ -872,6 +874,7 @@ impl Expr {
///
/// [`is_const()`]: LiteralExpr::is_const
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
#[serde(transparent)]
pub struct LiteralExpr {
value: Value,
}
Expand Down
85 changes: 85 additions & 0 deletions src/graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ impl ElemType for u32 {

/// Variant storage for a vector value.
#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)]
#[serde(from = "VectorValueEnum", into = "VectorValueEnum")]
pub struct VectorValue {
vector_type: VectorType,
storage: [u32; 4],
Expand Down Expand Up @@ -1203,6 +1204,90 @@ impl From<Vec4> for VectorValue {
}
}

/// Helper used as placeholder instead of [`VectorValue`] for serialization.
///
/// This enables serializing [`VectorValue`] as a glam type enum, instead of the
/// compressed binary runtime representation actually stored inside
/// [`VectorValue`].
#[derive(Serialize, Deserialize)]
enum VectorValueEnum {
BVec2(BVec2),
BVec3(BVec3),
BVec4(BVec4),
IVec2(IVec2),
IVec3(IVec3),
IVec4(IVec4),
UVec2(UVec2),
UVec3(UVec3),
UVec4(UVec4),
Vec2(Vec2),
Vec3(Vec3),
Vec4(Vec4),
}

impl From<VectorValueEnum> for VectorValue {
fn from(value: VectorValueEnum) -> Self {
match value {
VectorValueEnum::BVec2(v) => VectorValue::new_bvec2(v),
VectorValueEnum::BVec3(v) => VectorValue::new_bvec3(v),
VectorValueEnum::BVec4(v) => VectorValue::new_bvec4(v),
VectorValueEnum::IVec2(v) => VectorValue::new_ivec2(v),
VectorValueEnum::IVec3(v) => VectorValue::new_ivec3(v),
VectorValueEnum::IVec4(v) => VectorValue::new_ivec4(v),
VectorValueEnum::UVec2(v) => VectorValue::new_uvec2(v),
VectorValueEnum::UVec3(v) => VectorValue::new_uvec3(v),
VectorValueEnum::UVec4(v) => VectorValue::new_uvec4(v),
VectorValueEnum::Vec2(v) => VectorValue::new_vec2(v),
VectorValueEnum::Vec3(v) => VectorValue::new_vec3(v),
VectorValueEnum::Vec4(v) => VectorValue::new_vec4(v),
}
}
}

impl From<VectorValue> for VectorValueEnum {
fn from(value: VectorValue) -> Self {
let count = value.vector_type.count();
match value.elem_type() {
ScalarType::Bool => {
if count == 2 {
VectorValueEnum::BVec2(value.as_bvec2())
} else if count == 3 {
VectorValueEnum::BVec3(value.as_bvec3())
} else {
VectorValueEnum::BVec4(value.as_bvec4())
}
}
ScalarType::Int => {
if count == 2 {
VectorValueEnum::IVec2(value.as_ivec2())
} else if count == 3 {
VectorValueEnum::IVec3(value.as_ivec3())
} else {
VectorValueEnum::IVec4(value.as_ivec4())
}
}
ScalarType::Uint => {
if count == 2 {
VectorValueEnum::UVec2(value.as_uvec2())
} else if count == 3 {
VectorValueEnum::UVec3(value.as_uvec3())
} else {
VectorValueEnum::UVec4(value.as_uvec4())
}
}
ScalarType::Float => {
if count == 2 {
VectorValueEnum::Vec2(value.as_vec2())
} else if count == 3 {
VectorValueEnum::Vec3(value.as_vec3())
} else {
VectorValueEnum::Vec4(value.as_vec4())
}
}
}
}
}

/// Floating-point matrix value.
#[derive(Debug, Clone, Copy, Reflect, Serialize, Deserialize)]
pub struct MatrixValue {
Expand Down

0 comments on commit 9d8d81f

Please sign in to comment.