• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

djeedai / bevy_hanabi / 27069487078

06 Jun 2026 05:47PM UTC coverage: 58.459% (+0.8%) from 57.667%
27069487078

push

github

web-flow
Serialization through Bevy's type registry (#534)

This change transitions from the `typetag` dependency to using Bevy's
own built-in `TypeRegistry` to serialize and deserialize Hanabi's
`EffectAsset` (`*.effect`).

This solves a long-standing issue where modifiers couldn't be serialized
easily, and user-provided modifiers were ignored for serialization. With
the use of Bevy's own type registry, all built-in and user modifiers are
treated equally, as long as they are registered via
`register_reflect_modifier()`. All built-in modifiers are automatically
registered by the `HanabiPlugin`.

That registration allows leveraging the new `ReflectModifier` type data,
which provides a factory function to create a concrete modifier type
instance.  This is used during deserialization to instantiate the actual
modifier object.  This works around the lack of reflection/serialization
support for `Box<dyn Trait>`.

This change has a few knock-on effects on other parts of Hanabi:
- `EffectAsset::mesh` is now an `Option<AssetPath<'static>>` referencing
  the mesh, if any, used to render particles. That path is now also
  serialized.
- At runtime, the new `EffectMesh` component can override this asset
  mesh.

With this, `EffectAsset` is now entirely serializable. This doesn't
solve the entire asset story, as some additional items are still missing
(notably, textures). But this should greatly improve the value
proposition for loading Hanabi effects from assets on disk, rather than
generating effects in code.

280 of 410 new or added lines in 6 files covered. (68.29%)

8 existing lines in 2 files now uncovered.

5121 of 8760 relevant lines covered (58.46%)

190.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.77
/src/graph/expr.rs
1
//! Expression API
2
//!
3
//! This module contains the low-level _Expression API_, designed to produce
4
//! highly customizable modifier behaviors through a code-first API focused on
5
//! runtime and serialization. For asset editing, the higher-level [Node API]
6
//! offers an easier-to-use abstraction built on top of the Expression API.
7
//!
8
//! # Modules and expressions
9
//!
10
//! A particle effect is composed of a series [`Modifier`]s decribing how to
11
//! initialize and update (simulate) the particles of the effect. Choosing which
12
//! modifier to add to an effect provides the user some limited level of
13
//! customizing. However modifiers alone cannot provide enough customizing to
14
//! build visual effects. For this reason, modifier inputs can be further
15
//! customized with _expressions_. An expression produces a value which is
16
//! assigned to the input. That value can be constant, in which case it will be
17
//! hard-coded into the generated WGSL shader, for performance reasons.
18
//! Alternatively, that value can vary based on other quantities, like an effect
19
//! property, a particle attribute, or some built-in simulation variable like
20
//! the simulation time.
21
//!
22
//! An expression is represented by the [`Expr`] enum. Expressions can be
23
//! combined together to form more complex expression; for example, the Add
24
//! expression computes the sum between two other expressions. [`Expr`]
25
//! represents a form of abstraction over the actual WGSL shader code, and is
26
//! generally closely related to the actual expressions of the WGSL language
27
//! itself.
28
//!
29
//! An expression often refers to other expressions. However, [`Expr`] as an
30
//! enum cannot directly contain other [`Expr`], otherwise the type would become
31
//! infinitely recursive. Instead, each expression is stored into a [`Module`]
32
//! and indexed by an [`ExprHandle`], a non-zero index referencing the
33
//! expression inside the module. This indirection avoids the recursion issue.
34
//! This means all expressions are implicitly associated with a unique module,
35
//! and care must be taken to not mix exressions from different modules.
36
//!
37
//! Each [`EffectAsset`] contains a single [`Module`] storing all the [`Expr`]
38
//! used in all its modifiers.
39
//!
40
//! # Kinds of expressions
41
//!
42
//! Expressions can be grouped into various kinds, for the sake of
43
//! comprehension:
44
//! - Literal expressions represent a constant, which will be hard-coded into
45
//!   the final WGSL shader code. Expressions like `1.42` or `vec3<f32>(0.)` are
46
//!   literal expressions in WGSL, and are represented by a [`LiteralExpr`].
47
//! - Built-in expressions represent specific built-in values provided by the
48
//!   simulation context. For example, the current simulation time is a built-in
49
//!   expression accessible from the shader code of any visual effect to animate
50
//!   it. A built-in expression is represented by a [`BuiltInExpr`].
51
//! - Attribute expressions represent the value of an attribute of a particle. A
52
//!   typical example is the particle position, represented by
53
//!   [`Attribute::POSITION`], which can be obtained as an expression through an
54
//!   [`AttributeExpr`].
55
//! - Property expressions represent the value of a visual effect property, a
56
//!   quantity assigned by the user on the CPU side and uploaded each frame into
57
//!   the GPU for precise per-frame control over an effect. It's represented by
58
//!   a [`PropertyExpr`].
59
//! - Unary and binary operations are expressions taking one or two operand
60
//!   expressions and transforming them. A typical example is the Add operator,
61
//!   which takes two operand expressions and produces their sum.
62
//!
63
//! # Building expressions
64
//!
65
//! The fundamental way to build expressions is to directly write them into a
66
//! [`Module`] itself. The [`Module`] type contains various methods to create
67
//! new expressions and immediately write them.
68
//!
69
//! ```
70
//! # use bevy_hanabi::*;
71
//! let mut module = Module::default();
72
//!
73
//! // Build and write a literal expression into the module.
74
//! let expr = module.lit(3.42);
75
//! ```
76
//!
77
//! Due to the code-first nature of the Expression API however, that approach
78
//! can be very verbose. Instead, users are encouraged to use an [`ExprWriter`],
79
//! a simple utility to build expressions with a shortened syntax. Once an
80
//! expression is built, it can be written into the underlying [`Module`]. This
81
//! approach generally makes the code more readable, and is therefore highly
82
//! encouraged, but is not mandatory.
83
//!
84
//! ```
85
//! # use bevy_hanabi::*;
86
//! // Create a writer owning a new Module
87
//! let mut w = ExprWriter::new();
88
//!
89
//! // Build a complex expression: max(3.42, properties.my_prop)
90
//! let prop = w.add_property("my_property", 3.0.into());
91
//! let expr = w.lit(3.42).max(w.prop(prop));
92
//!
93
//! // Finalize the expression and write it into the Module. The returned handle can
94
//! // be assign to a modifier input.
95
//! let handle = expr.expr();
96
//!
97
//! // Finish using the writer and recover the Module with all written expressions
98
//! let module = w.finish();
99
//! ```
100
//!
101
//! [Node API]: crate::graph::node
102
//! [`Modifier`]: crate::Modifier
103
//! [`EffectAsset`]: crate::EffectAsset
104

105
use std::{cell::RefCell, num::NonZeroU32, rc::Rc};
106

107
use bevy::{
108
    platform::collections::HashSet,
109
    prelude::default,
110
    reflect::{Reflect, ReflectDeserialize, ReflectSerialize},
111
};
112
use serde::{Deserialize, Serialize};
113
use thiserror::Error;
114

115
use super::Value;
116
use crate::{
117
    Attribute, ModifierContext, ParticleLayout, Property, PropertyLayout, ScalarType,
118
    TextureLayout, TextureSlot, ToWgslString, ValueType, VectorType,
119
};
120

121
/// A one-based ID into a collection of a [`Module`].
122
type Id = NonZeroU32;
123

124
/// Handle of an expression inside a given [`Module`].
125
///
126
/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a
127
/// lightweight representation, similar to a simple array index. For this
128
/// reason, it's easily copyable. However it's also lacking any kind of error
129
/// checking, and mixing handles to different modules produces undefined
130
/// behaviors (like an index does when indexing the wrong array).
131
///
132
/// # Serialization
133
///
134
/// [`ExprHandle`] is serialized as a string `#<id>`, where `<id>` is the
135
/// 1-based integer index of the expression in the implicitly associated
136
/// [`Module`]'s expression array. Valid `<id>` values are in the range
137
/// `1..=u32::MAX`.
138
///
139
/// Note that during deserialization, there is no validation that the index
140
/// actually refers to a valid entry in the expression array.
141
///
142
/// Examples of valid values:
143
/// - `"#1"`
144
/// - `"#42"`
145
/// - `"#4000"` -- deserializes OK, but unlikely there are 4000 expressions in
146
///   the Module
147
///
148
/// Examples of **invalid** values:
149
/// - `"#0"` -- 0 is a reserved value
150
/// - `"#-1"` -- must be positive
151
/// - `"#4294967296"` -- out of bounds (> u32::MAX)
152
/// - `33` -- not a string
153
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect)]
154
#[reflect(Serialize, Deserialize)]
155
#[repr(transparent)]
156
pub struct ExprHandle {
157
    id: Id,
158
}
159

160
impl serde::Serialize for ExprHandle {
161
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
11✔
162
    where
163
        S: serde::Serializer,
164
    {
165
        serializer.serialize_str(&format!("#{}", self.id.get()))
44✔
166
    }
167
}
168

169
impl<'de> serde::Deserialize<'de> for ExprHandle {
170
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
18✔
171
    where
172
        D: serde::Deserializer<'de>,
173
    {
174
        struct IdVisitor;
175

NEW
176
        impl<'de2> serde::de::Visitor<'de2> for IdVisitor {
×
177
            type Value = ExprHandle;
178

179
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1✔
180
                formatter.write_str(
2✔
181
                    "a string of the form \"#<N>\" where <N> is a non-zero expression index",
182
                )
183
            }
184

185
            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
17✔
186
            where
187
                E: serde::de::Error,
188
            {
189
                if v.len() > 1 && v.chars().nth(0) == Some('#') {
34✔
190
                    let id = v[1..]
30✔
191
                        .parse::<u32>()
192
                        .map_err(|_| serde::de::Error::custom("Failed to parse ID value"))?;
20✔
NEW
193
                    NonZeroU32::try_from(id)
×
194
                        .map(|id| ExprHandle { id })
26✔
195
                        .map_err(|_| serde::de::Error::custom("Invalid ID value"))
1✔
196
                } else {
197
                    Err(serde::de::Error::custom(
1✔
198
                        "Invalid ID format (expected '#N')",
1✔
199
                    ))
200
                }
201
            }
202

NEW
203
            fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
×
204
            where
205
                E: serde::de::Error,
206
            {
NEW
207
                self.visit_str(&v[..])
×
208
            }
209
        }
210

211
        deserializer.deserialize_any(IdVisitor)
54✔
212
    }
213
}
214

215
impl ExprHandle {
216
    /// Create a new handle from a 1-based [`Id`].
217
    #[allow(dead_code)]
218
    fn new(id: Id) -> Self {
×
219
        Self { id }
220
    }
221

222
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
223
    /// the index is known to be non-zero already.
224
    #[allow(unsafe_code)]
225
    unsafe fn new_unchecked(id: usize) -> Self {
511✔
226
        debug_assert!(id != 0);
1,022✔
227
        Self {
228
            id: NonZeroU32::new_unchecked(id as u32),
511✔
229
        }
230
    }
231

232
    /// Get the zero-based index into the array of the module.
233
    pub fn index(&self) -> usize {
434✔
234
        (self.id.get() - 1) as usize
434✔
235
    }
236
}
237

238
/// Handle of a property inside a given [`Module`].
239
///
240
/// A handle uniquely references a [`Property`] stored inside a [`Module`]. It's
241
/// a lightweight representation, similar to a simple array index. For this
242
/// reason, it's easily copyable. However it's also lacking any kind of error
243
/// checking, and mixing handles to different modules produces undefined
244
/// behaviors (like an index does when indexing the wrong array).
245
#[derive(
246
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
247
)]
248
#[repr(transparent)]
249
#[serde(transparent)]
250
pub struct PropertyHandle {
251
    id: Id,
252
}
253

254
impl PropertyHandle {
255
    /// Create a new handle from a 1-based [`Id`].
256
    #[allow(dead_code)]
257
    fn new(id: Id) -> Self {
×
258
        Self { id }
259
    }
260

261
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
262
    /// the index is known to be non-zero already.
263
    #[allow(unsafe_code)]
264
    unsafe fn new_unchecked(id: usize) -> Self {
7✔
265
        debug_assert!(id != 0);
14✔
266
        Self {
267
            id: NonZeroU32::new_unchecked(id as u32),
7✔
268
        }
269
    }
270

271
    /// Get the zero-based index into the array of the module.
272
    pub fn index(&self) -> usize {
2✔
273
        (self.id.get() - 1) as usize
2✔
274
    }
275
}
276

277
/// Handle of a texture inside a given [`Module`].
278
///
279
/// A handle uniquely references a [`TextureSlot`] stored inside a [`Module`].
280
/// It's a lightweight representation, similar to a simple array index. For this
281
/// reason, it's easily copyable. However it's also lacking any kind of error
282
/// checking, and mixing handles to different modules produces undefined
283
/// behaviors (like an index does when indexing the wrong array).
284
#[derive(
285
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
286
)]
287
#[repr(transparent)]
288
#[serde(transparent)]
289
pub struct TextureHandle {
290
    id: Id,
291
}
292

293
impl TextureHandle {
294
    /// Create a new handle from a 1-based [`Id`].
295
    #[allow(dead_code)]
296
    fn new(id: Id) -> Self {
×
297
        Self { id }
298
    }
299

300
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
301
    /// the index is known to be non-zero already.
302
    #[allow(unsafe_code)]
303
    unsafe fn new_unchecked(id: usize) -> Self {
×
304
        debug_assert!(id != 0);
×
305
        Self {
306
            id: NonZeroU32::new_unchecked(id as u32),
×
307
        }
308
    }
309

310
    /// Get the zero-based index into the array of the module.
311
    #[allow(dead_code)]
312
    fn index(&self) -> usize {
×
313
        (self.id.get() - 1) as usize
×
314
    }
315
}
316

317
/// Container for expressions.
318
///
319
/// A module represents a storage for a set of expressions used in a single
320
/// [`EffectAsset`]. Modules are not reusable accross effect assets; each effect
321
/// asset owns a single module, containing all the expressions used in all the
322
/// modifiers attached to that asset. However, for convenience, a module can be
323
/// cloned into an unrelated module, and the clone can be assigned to another
324
/// effect asset.
325
///
326
/// Modules are built incrementally. Expressions are written into the module
327
/// through convenience helpers like [`lit()`] or [`attr()`]. Alternatively, an
328
/// [`ExprWriter`] can be used to populate a new or existing module. Either way,
329
/// once an expression is written into a module, it cannot be modified or
330
/// deleted. Modules are not designed to be used as editing structures, but as
331
/// storage and serialization ones.
332
///
333
/// [`EffectAsset`]: crate::EffectAsset
334
/// [`lit()`]: Module::lit
335
/// [`attr()`]: Module::attr
336
#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)]
337
pub struct Module {
338
    /// Expressions defined in the module.
339
    expressions: Vec<Expr>,
340
    /// Properties used as part of a [`PropertyExpr`].
341
    properties: Vec<Property>,
342
    /// Texture layout.
343
    texture_layout: TextureLayout,
344
}
345

346
macro_rules! impl_module_unary {
347
    ($t: ident, $T: ident) => {
348
        #[doc = concat!("Build a [`UnaryOperator::", stringify!($T), "`](crate::graph::expr::UnaryOperator::", stringify!($T),") unary expression and append it to the module.\n\nThis is a shortcut for [`unary(UnaryOperator::", stringify!($T), ", inner)`](crate::graph::expr::Module::unary).")]
349
        #[inline]
350
        pub fn $t(&mut self, inner: ExprHandle) -> ExprHandle {
38✔
351
            self.unary(UnaryOperator::$T, inner)
152✔
352
        }
353
    };
354
}
355

356
macro_rules! impl_module_binary {
357
    ($t: ident, $T: ident) => {
358
        #[doc = concat!("Build a [`BinaryOperator::", stringify!($T), "`](crate::graph::expr::BinaryOperator::", stringify!($T),") binary expression and append it to the module.\n\nThis is a shortcut for [`binary(BinaryOperator::", stringify!($T), ", left, right)`](crate::graph::expr::Module::binary).")]
359
        #[inline]
360
        pub fn $t(&mut self, left: ExprHandle, right: ExprHandle) -> ExprHandle {
35✔
361
            self.binary(BinaryOperator::$T, left, right)
175✔
362
        }
363
    };
364
}
365

366
macro_rules! impl_module_ternary {
367
    ($t: ident, $T: ident) => {
368
        #[doc = concat!("Build a [`TernaryOperator::", stringify!($T), "`](crate::graph::expr::TernaryOperator::", stringify!($T),") ternary expression and append it to the module.\n\nThis is a shortcut for [`ternary(TernaryOperator::", stringify!($T), ", first, second, third)`](crate::graph::expr::Module::ternary).")]
369
        #[inline]
370
        pub fn $t(&mut self, first: ExprHandle, second: ExprHandle, third: ExprHandle) -> ExprHandle {
5✔
371
            self.ternary(TernaryOperator::$T, first, second, third)
30✔
372
        }
373
    };
374
}
375

376
impl Module {
377
    /// Create a new module from an existing collection of expressions.
378
    pub fn from_raw(expr: Vec<Expr>) -> Self {
×
379
        Self {
380
            expressions: expr,
381
            properties: vec![],
×
382
            texture_layout: default(),
×
383
        }
384
    }
385

386
    /// Get all the expressions in this module.
387
    pub fn expressions(&self) -> impl Iterator<Item = (ExprHandle, &Expr)> {
1✔
388
        self.expressions.iter().enumerate().map(|(index, expr)| {
9✔
389
            (
390
                // SAFETY - We directly iterate over the array with enumerate() so all indices are
391
                // valid by design.
392
                #[allow(unsafe_code)]
6✔
393
                unsafe {
6✔
394
                    ExprHandle::new_unchecked(index + 1)
12✔
395
                },
396
                expr,
6✔
397
            )
398
        })
399
    }
400

401
    /// Append a new expression to the module.
402
    pub fn add_expr(&mut self, expr: impl Into<Expr>) -> ExprHandle {
504✔
403
        self.expressions.push(expr.into());
2,016✔
404
        #[allow(unsafe_code)]
×
405
        unsafe {
406
            ExprHandle::new_unchecked(self.expressions.len())
1,512✔
407
        }
408
    }
409

410
    /// Add a new property to the module.
411
    ///
412
    /// See [`Property`] for more details on what effect properties are.
413
    ///
414
    /// # Panics
415
    ///
416
    /// Panics if a property with the same name already exists.
417
    pub fn add_property(
7✔
418
        &mut self,
419
        name: impl Into<String>,
420
        default_value: Value,
421
    ) -> PropertyHandle {
422
        let name = name.into();
21✔
423
        assert!(!self.properties.iter().any(|p| p.name() == name));
23✔
424
        self.properties.push(Property::new(name, default_value));
7✔
425
        // SAFETY - We just pushed a new property into the array, so its length is
426
        // non-zero.
427
        #[allow(unsafe_code)]
×
428
        unsafe {
429
            PropertyHandle::new_unchecked(self.properties.len())
×
430
        }
431
    }
432

433
    /// Get an existing property by handle.
434
    ///
435
    /// Existing properties are properties previously created with
436
    /// [`add_property()`].
437
    ///
438
    /// [`add_property()`]: crate::Module::add_property
439
    pub fn get_property(&self, property: PropertyHandle) -> Option<&Property> {
2✔
440
        self.properties.get(property.index())
6✔
441
    }
442

443
    /// Get an existing property by name.
444
    ///
445
    /// Existing properties are properties previously created with
446
    /// [`add_property()`].
447
    ///
448
    /// [`add_property()`]: crate::Module::add_property
449
    pub fn get_property_by_name(&self, name: &str) -> Option<PropertyHandle> {
×
450
        self.properties
×
451
            .iter()
452
            .enumerate()
453
            .find(|(_, prop)| prop.name() == name)
×
454
            .map(|(index, _)| PropertyHandle::new(NonZeroU32::new(index as u32 + 1).unwrap()))
×
455
    }
456

457
    /// Get the list of existing properties.
458
    pub fn properties(&self) -> &[Property] {
326✔
459
        &self.properties
326✔
460
    }
461

462
    /// Add a new texture slot to the module.
463
    ///
464
    /// The `name` parameter defines a new [`TextureSlot`] associated with this
465
    /// module, and must be unique inside this module. A unique index is also
466
    /// associated with the slot, corresponding to the value returned by
467
    /// [`TextureLayout::get_slot_by_name()`].
468
    ///
469
    /// Once a slot is added, an actual texture resource, defined by its
470
    /// `Handle<Image>`, is bound to that slot through the
471
    /// [`EffectMaterial`] component. Expressions like [`TextureSampleExpr`] can
472
    /// be used to sample the texture using the returned [`TextureHandle`].
473
    ///
474
    /// # Returns
475
    ///
476
    /// The handle of the texture inside this module. This handle is used in
477
    /// expressions like the [`TextureSampleExpr`] to reference this texture
478
    /// slot.
479
    ///
480
    /// # Panics
481
    ///
482
    /// Panics if a texture slot with the same name already exists inside this
483
    /// module. Different effect asset (different modules) can have the same
484
    /// slot name.
485
    ///
486
    /// [`EffectMaterial`]: crate::EffectMaterial
487
    pub fn add_texture_slot(&mut self, name: impl Into<String>) -> TextureHandle {
×
488
        let name = name.into();
×
489
        assert!(!self.texture_layout.layout.iter().any(|t| t.name == name));
×
490
        self.texture_layout.layout.push(TextureSlot { name });
×
491
        // SAFETY - We just pushed a new slot into the array, so its length is non-zero.
492
        #[allow(unsafe_code)]
×
493
        unsafe {
494
            TextureHandle::new_unchecked(self.texture_layout.layout.len())
×
495
        }
496
    }
497

498
    /// Insert into the given set all attributes referenced by any
499
    /// [`AttributeExpr`] present in the module.
500
    ///
501
    /// Note that this **excludes** the attributes from an
502
    /// [`Expr::ParentAttribute`] expression.
503
    pub fn gather_attributes(&self, set: &mut HashSet<Attribute>) {
648✔
504
        for expr in &self.expressions {
1,896✔
505
            if let Expr::Attribute(attr) = expr {
1✔
506
                set.insert(attr.attr);
507
            }
508
        }
509
    }
510

511
    /// Build a literal expression and append it to the module.
512
    #[inline]
513
    pub fn lit<V>(&mut self, value: V) -> ExprHandle
339✔
514
    where
515
        Value: From<V>,
516
    {
517
        self.add_expr(Expr::Literal(LiteralExpr::new(value)))
1,017✔
518
    }
519

520
    /// Build an attribute expression and append it to the module.
521
    #[inline]
522
    pub fn attr(&mut self, attr: Attribute) -> ExprHandle {
31✔
523
        self.add_expr(Expr::Attribute(AttributeExpr::new(attr)))
93✔
524
    }
525

526
    /// Build a parent attribute expression and append it to the module.
527
    #[inline]
528
    pub fn parent_attr(&mut self, attr: Attribute) -> ExprHandle {
×
529
        self.add_expr(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
530
    }
531

532
    /// Build a property expression and append it to the module.
533
    ///
534
    /// A property expression retrieves the value of the given property.
535
    #[inline]
536
    pub fn prop(&mut self, property: PropertyHandle) -> ExprHandle {
3✔
537
        self.add_expr(Expr::Property(PropertyExpr::new(property)))
9✔
538
    }
539

540
    /// Build a built-in expression and append it to the module.
541
    #[inline]
542
    pub fn builtin(&mut self, op: BuiltInOperator) -> ExprHandle {
30✔
543
        self.add_expr(Expr::BuiltIn(BuiltInExpr::new(op)))
90✔
544
    }
545

546
    /// Build a unary expression and append it to the module.
547
    ///
548
    /// The handle to the expression representing the operand of the unary
549
    /// operation must be valid, that is reference an expression
550
    /// contained in the current [`Module`].
551
    ///
552
    /// # Panics
553
    ///
554
    /// Panics in some cases if the operand handle do not reference an existing
555
    /// expression in the current module. Note however that this check can
556
    /// miss some invalid handles (false negative), so only represents an
557
    /// extra safety net that users shouldn't rely exclusively on
558
    /// to ensure the operand handles are valid. Instead, it's the
559
    /// responsibility of the user to ensure the operand handle references an
560
    /// existing expression in the current [`Module`].
561
    #[inline]
562
    pub fn unary(&mut self, op: UnaryOperator, inner: ExprHandle) -> ExprHandle {
38✔
563
        assert!(inner.index() < self.expressions.len());
152✔
564
        self.add_expr(Expr::Unary { op, expr: inner })
114✔
565
    }
566

567
    impl_module_unary!(abs, Abs);
568
    impl_module_unary!(acos, Acos);
569
    impl_module_unary!(asin, Asin);
570
    impl_module_unary!(atan, Atan);
571
    impl_module_unary!(all, All);
572
    impl_module_unary!(any, Any);
573
    impl_module_unary!(ceil, Ceil);
574
    impl_module_unary!(cos, Cos);
575
    impl_module_unary!(exp, Exp);
576
    impl_module_unary!(exp2, Exp2);
577
    impl_module_unary!(floor, Floor);
578
    impl_module_unary!(fract, Fract);
579
    impl_module_unary!(inverse_sqrt, InvSqrt);
580
    impl_module_unary!(length, Length);
581
    impl_module_unary!(log, Log);
582
    impl_module_unary!(log2, Log2);
583
    impl_module_unary!(normalize, Normalize);
584
    impl_module_unary!(pack4x8snorm, Pack4x8snorm);
585
    impl_module_unary!(pack4x8unorm, Pack4x8unorm);
586
    impl_module_unary!(round, Round);
587
    impl_module_unary!(saturate, Saturate);
588
    impl_module_unary!(sign, Sign);
589
    impl_module_unary!(sin, Sin);
590
    impl_module_unary!(sqrt, Sqrt);
591
    impl_module_unary!(tan, Tan);
592
    impl_module_unary!(unpack4x8snorm, Unpack4x8snorm);
593
    impl_module_unary!(unpack4x8unorm, Unpack4x8unorm);
594
    impl_module_unary!(w, W);
595
    impl_module_unary!(x, X);
596
    impl_module_unary!(y, Y);
597
    impl_module_unary!(z, Z);
598

599
    /// Build a binary expression and append it to the module.
600
    ///
601
    /// The handles to the expressions representing the left and right operands
602
    /// of the binary operation must be valid, that is reference expressions
603
    /// contained in the current [`Module`].
604
    ///
605
    /// # Panics
606
    ///
607
    /// Panics in some cases if either of the left or right operand handles do
608
    /// not reference existing expressions in the current module. Note however
609
    /// that this check can miss some invalid handles (false negative), so only
610
    /// represents an extra safety net that users shouldn't rely exclusively on
611
    /// to ensure the operand handles are valid. Instead, it's the
612
    /// responsibility of the user to ensure handles reference existing
613
    /// expressions in the current [`Module`].
614
    #[inline]
615
    pub fn binary(
35✔
616
        &mut self,
617
        op: BinaryOperator,
618
        left: ExprHandle,
619
        right: ExprHandle,
620
    ) -> ExprHandle {
621
        assert!(left.index() < self.expressions.len());
140✔
622
        assert!(right.index() < self.expressions.len());
140✔
623
        self.add_expr(Expr::Binary { op, left, right })
140✔
624
    }
625

626
    impl_module_binary!(add, Add);
627
    impl_module_binary!(atan2, Atan2);
628
    impl_module_binary!(cross, Cross);
629
    impl_module_binary!(distance, Distance);
630
    impl_module_binary!(div, Div);
631
    impl_module_binary!(dot, Dot);
632
    impl_module_binary!(ge, GreaterThanOrEqual);
633
    impl_module_binary!(gt, GreaterThan);
634
    impl_module_binary!(le, LessThanOrEqual);
635
    impl_module_binary!(lt, LessThan);
636
    impl_module_binary!(max, Max);
637
    impl_module_binary!(min, Min);
638
    impl_module_binary!(mul, Mul);
639
    impl_module_binary!(rem, Remainder);
640
    impl_module_binary!(step, Step);
641
    impl_module_binary!(sub, Sub);
642
    impl_module_binary!(uniform, UniformRand);
643
    impl_module_binary!(normal, NormalRand);
644
    impl_module_binary!(vec2, Vec2);
645
    impl_module_binary!(vec4_xyz_w, Vec4XyzW);
646

647
    /// Build a ternary expression and append it to the module.
648
    ///
649
    /// The handles to the expressions representing the three operands of the
650
    /// ternary operation must be valid, that is reference expressions
651
    /// contained in the current [`Module`].
652
    ///
653
    /// # Panics
654
    ///
655
    /// Panics in some cases if any of the operand handles do not reference
656
    /// existing expressions in the current module. Note however
657
    /// that this check can miss some invalid handles (false negative), so only
658
    /// represents an extra safety net that users shouldn't rely exclusively on
659
    /// to ensure the operand handles are valid. Instead, it's the
660
    /// responsibility of the user to ensure handles reference existing
661
    /// expressions in the current [`Module`].
662
    #[inline]
663
    pub fn ternary(
5✔
664
        &mut self,
665
        op: TernaryOperator,
666
        first: ExprHandle,
667
        second: ExprHandle,
668
        third: ExprHandle,
669
    ) -> ExprHandle {
670
        assert!(first.index() < self.expressions.len());
20✔
671
        assert!(second.index() < self.expressions.len());
20✔
672
        assert!(third.index() < self.expressions.len());
20✔
673
        self.add_expr(Expr::Ternary {
15✔
674
            op,
10✔
675
            first,
10✔
676
            second,
5✔
677
            third,
5✔
678
        })
679
    }
680

681
    impl_module_ternary!(mix, Mix);
682
    impl_module_ternary!(clamp, Clamp);
683
    impl_module_ternary!(smoothstep, SmoothStep);
684
    impl_module_ternary!(vec3, Vec3);
685

686
    /// Build a cast expression and append it to the module.
687
    ///
688
    /// The handle to the expressions representing the operand of the cast
689
    /// operation must be valid, that is reference expressions contained in
690
    /// the current [`Module`].
691
    ///
692
    /// # Panics
693
    ///
694
    /// Panics in some cases if the operand handle does not reference existing
695
    /// expressions in the current module. Note however that this check can
696
    /// miss some invalid handles (false negative), so only represents an
697
    /// extra safety net that users shouldn't rely exclusively on
698
    /// to ensure the operand handles are valid. Instead, it's the
699
    /// responsibility of the user to ensure handles reference existing
700
    /// expressions in the current [`Module`].
701
    ///
702
    /// Panics if the resulting cast expression is not valid. See
703
    /// [`CastExpr::is_valid()`] for the exact meaning.
704
    pub fn cast(&mut self, expr: ExprHandle, target: impl Into<ValueType>) -> ExprHandle {
9✔
705
        assert!(expr.index() < self.expressions.len());
36✔
706
        let target = target.into();
27✔
707
        let expr = CastExpr::new(expr, target);
36✔
708
        if let Some(valid) = expr.is_valid(self) {
27✔
709
            assert!(valid);
×
710
        }
711
        self.add_expr(Expr::Cast(expr))
4✔
712
    }
713

714
    /// Get an existing expression from its handle.
715
    #[inline]
716
    pub fn get(&self, expr: ExprHandle) -> Option<&Expr> {
20✔
717
        let index = expr.index();
60✔
718
        self.expressions.get(index)
40✔
719
    }
720

721
    /// Get an existing expression from its handle.
722
    #[inline]
723
    pub fn get_mut(&mut self, expr: ExprHandle) -> Option<&mut Expr> {
2✔
724
        let index = expr.index();
6✔
725
        self.expressions.get_mut(index)
4✔
726
    }
727

728
    /// Get an existing expression from its handle.
729
    #[inline]
730
    pub fn try_get(&self, expr: ExprHandle) -> Result<&Expr, ExprError> {
272✔
731
        let index = expr.index();
816✔
732
        self.expressions
544✔
733
            .get(index)
272✔
734
            .ok_or(ExprError::InvalidExprHandleError(format!(
544✔
735
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
272✔
736
    }
737

738
    /// Get an existing expression from its handle.
739
    #[inline]
740
    pub fn try_get_mut(&mut self, expr: ExprHandle) -> Result<&mut Expr, ExprError> {
2✔
741
        let index = expr.index();
6✔
742
        self.expressions
4✔
743
            .get_mut(index)
2✔
744
            .ok_or(ExprError::InvalidExprHandleError(format!(
4✔
745
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
2✔
746
    }
747

748
    /// Is the expression resulting in a compile-time constant which can be
749
    /// hard-coded into a shader's code?
750
    ///
751
    /// # Panics
752
    ///
753
    /// Panics if `expr` doesn't refer to an expression of this module.
754
    #[inline]
755
    pub fn is_const(&self, expr: ExprHandle) -> bool {
×
756
        let expr = self.get(expr).unwrap();
×
757
        expr.is_const(self)
×
758
    }
759

760
    /// Has the expression any side-effect?
761
    ///
762
    /// Expressions with side-effect need to be stored into temporary variables
763
    /// when the shader code is emitted, so that the side effect is only applied
764
    /// once when the expression is reused in multiple locations.
765
    ///
766
    /// # Panics
767
    ///
768
    /// Panics if `expr` doesn't refer to an expression of this module.
769
    pub fn has_side_effect(&self, expr: ExprHandle) -> bool {
×
770
        let expr = self.get(expr).unwrap();
×
771
        expr.has_side_effect(self)
×
772
    }
773

774
    /// Get the texture layout of this module.
775
    pub fn texture_layout(&self) -> TextureLayout {
342✔
776
        self.texture_layout.clone()
684✔
777
    }
778
}
779

780
/// Errors raised when manipulating expressions [`Expr`] and node graphs
781
/// [`Graph`].
782
///
783
/// [`Graph`]: crate::graph::Graph
784
#[derive(Debug, Clone, PartialEq, Eq, Error)]
785
pub enum ExprError {
786
    /// Expression type error.
787
    ///
788
    /// Generally used for invalid type conversion (casting).
789
    #[error("Type error: {0}")]
790
    TypeError(String),
791

792
    /// Expression syntax error.
793
    #[error("Syntax error: {0}")]
794
    SyntaxError(String),
795

796
    /// Generic graph evaluation error.
797
    #[error("Graph evaluation error: {0}")]
798
    GraphEvalError(String),
799

800
    /// Error resolving a property.
801
    ///
802
    /// An unknown property was not defined in the evaluation context, which
803
    /// usually means that the property was not defined with
804
    /// [`Module::add_property()`].
805
    #[error("Property error: {0}")]
806
    PropertyError(String),
807

808
    /// Invalid expression handle not referencing any existing [`Expr`] in the
809
    /// evaluation [`Module`].
810
    ///
811
    /// This error is commonly raised when using an [`ExprWriter`] and
812
    /// forgetting to transfer the underlying [`Module`] where the expressions
813
    /// are written to the [`EffectAsset`]. See [`ExprWriter`] for details.
814
    ///
815
    /// [`EffectAsset`]: crate::EffectAsset
816
    #[error("Invalid expression handle: {0}")]
817
    InvalidExprHandleError(String),
818

819
    /// Invalid modifier context.
820
    ///
821
    /// The operation was expecting a given [`ModifierContext`], but instead
822
    /// another [`ModifierContext`] was available.
823
    #[error("Invalid modifier context {0}, expected {1} instead.")]
824
    InvalidModifierContext(ModifierContext, ModifierContext),
825
}
826

827
/// Evaluation context for transforming expressions into WGSL code.
828
///
829
/// The evaluation context references a [`Module`] storing all [`Expr`] in use,
830
/// as well as a [`ParticleLayout`] defining the existing attributes of each
831
/// particle and their layout in memory, and a [`PropertyLayout`] defining
832
/// existing properties and their layout in memory. These together define the
833
/// context within which expressions are evaluated.
834
///
835
/// A same expression can be valid in one context and invalid in another. The
836
/// most obvious example is a [`PropertyExpr`] which is only valid if the
837
/// property is actually defined in the property layout of the evaluation
838
/// context.
839
pub trait EvalContext {
840
    /// Get the modifier context of the evaluation.
841
    fn modifier_context(&self) -> ModifierContext;
842

843
    /// Get the particle layout of the effect.
844
    fn particle_layout(&self) -> &ParticleLayout;
845

846
    /// Get the property layout of the effect.
847
    fn property_layout(&self) -> &PropertyLayout;
848

849
    /// Evaluate an expression, returning its WGSL shader code.
850
    ///
851
    /// The evaluation is guaranteed to be unique. Calling `eval()` multiple
852
    /// times with the same handle will return the same result. If the
853
    /// expression referenced by `handle` has side effects, it's evaluated only
854
    /// once on first call, stored in a local variable, and the variable cached
855
    /// and returned on subsequent calls.
856
    fn eval(&mut self, module: &Module, handle: ExprHandle) -> Result<String, ExprError>;
857

858
    /// Generate a unique local variable name.
859
    ///
860
    /// Each time this function is called, a new unique name is generated. The
861
    /// name is guaranteed to be unique within the current evaluation context
862
    /// only. Do not use for global top-level identifiers.
863
    ///
864
    /// The variable name is not registered automatically in the [`Module`]. If
865
    /// you call `make_local_var()` but doesn't use the returned name, it won't
866
    /// appear in the shader.
867
    fn make_local_var(&mut self) -> String;
868

869
    /// Push an intermediate statement during an evaluation.
870
    ///
871
    /// Intermediate statements are inserted before the expression evaluation
872
    /// which produced them. They're generally used to define temporary local
873
    /// variables, for example to store the result of expressions with side
874
    /// effects.
875
    fn push_stmt(&mut self, stmt: &str);
876

877
    /// Create a function.
878
    ///
879
    /// Create a new function with the given `func_name` inside the given
880
    /// [`Module`]. The function takes a list of arguments `args`, which are
881
    /// copied verbatim into the shader code without any validation. The body of
882
    /// the function is generated by invoking the given closure once with the
883
    /// input `module` and a temporary [`EvalContext`] local to the function.
884
    /// The closure must return the generated shader code of the function
885
    /// body. Any statement pushed to the temporary function context with
886
    /// [`EvalContext::push_stmt()`] is emitted inside the function body before
887
    /// the returned code. The function can subsequently be called from the
888
    /// parent context by generating code to call `func_name`, with the correct
889
    /// arguments.
890
    fn make_fn(
891
        &mut self,
892
        func_name: &str,
893
        args: &str,
894
        module: &mut Module,
895
        f: &mut dyn FnMut(&mut Module, &mut dyn EvalContext) -> Result<String, ExprError>,
896
    ) -> Result<(), ExprError>;
897

898
    /// Check if the particle attribute struct is a pointer?
899
    ///
900
    /// In some context the attribute struct (named 'particle' in WGSL code) is
901
    /// a pointer instead of being a struct instance. This happens in particular
902
    /// when defining a function for a modifier, and passing the attribute
903
    /// struct to be modified. In that case the generated code needs to emit
904
    /// a pointer indirection code to access the fields of the struct.
905
    fn is_attribute_pointer(&self) -> bool;
906
}
907

908
/// Language expression producing a value.
909
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
910
pub enum Expr {
911
    /// Built-in expression ([`BuiltInExpr`]).
912
    ///
913
    /// A built-in expression provides access to some internal
914
    /// quantities like the simulation time.
915
    BuiltIn(BuiltInExpr),
916

917
    /// Literal expression ([`LiteralExpr`]).
918
    ///
919
    /// A literal expression represents a shader constants.
920
    Literal(LiteralExpr),
921

922
    /// Property expression ([`PropertyExpr`]).
923
    ///
924
    /// A property expression represents the value of an [`EffectAsset`]'s
925
    /// property.
926
    ///
927
    /// [`EffectAsset`]: crate::EffectAsset
928
    Property(PropertyExpr),
929

930
    /// Attribute expression ([`AttributeExpr`]).
931
    ///
932
    /// An attribute expression represents the value of an attribute for a
933
    /// particle, like its position or velocity.
934
    Attribute(AttributeExpr),
935

936
    /// Attribute expression ([`AttributeExpr`]) from a parent effect.
937
    ///
938
    /// An attribute expression represents the value of an attribute for a
939
    /// particle, like its position or velocity. This attribute however refers
940
    /// to the parent particle which spawned this one, via GPU events.
941
    ///
942
    /// This attribute is only valid when used in init modifiers, from an effect
943
    /// with a parent effect (an effect which has an [`EffectParent`]
944
    /// component).
945
    ///
946
    /// [`EffectParent`]: crate::EffectParent
947
    ParentAttribute(AttributeExpr),
948

949
    /// Unary operation expression.
950
    ///
951
    /// A unary operation transforms an expression into another expression.
952
    Unary {
953
        /// Unary operator.
954
        op: UnaryOperator,
955
        /// Operand the unary operation applies to.
956
        expr: ExprHandle,
957
    },
958

959
    /// Binary operation expression.
960
    ///
961
    /// A binary operation composes two expressions into a third one.
962
    Binary {
963
        /// Binary operator.
964
        op: BinaryOperator,
965
        /// Left-hand side operand the binary operation applies to.
966
        left: ExprHandle,
967
        /// Right-hand side operand the binary operation applies to.
968
        right: ExprHandle,
969
    },
970

971
    /// Ternary operation expression.
972
    ///
973
    /// A ternary operation composes three expressions into a fourth one.
974
    Ternary {
975
        /// Ternary operator.
976
        op: TernaryOperator,
977
        /// First operand the ternary operation applies to.
978
        first: ExprHandle,
979
        /// Second operand the ternary operation applies to.
980
        second: ExprHandle,
981
        /// Third operand the ternary operation applies to.
982
        third: ExprHandle,
983
    },
984

985
    /// Cast expression.
986
    ///
987
    /// An expression to cast an expression to another type.
988
    Cast(CastExpr),
989

990
    /// Access to textures.
991
    ///
992
    /// An expression to sample a texture from the effect's material. Currently
993
    /// only color textures (returning a `vec4<f32>`) are supported.
994
    TextureSample(TextureSampleExpr),
995
}
996

997
impl Expr {
998
    /// Is the expression resulting in a compile-time constant which can be
999
    /// hard-coded into a shader's code?
1000
    ///
1001
    /// The [`Module`] passed as argument is the owning module of the
1002
    /// expression, which is used to recursively evaluate the const-ness of the
1003
    /// entire expression. For some expressions like literals or attributes or
1004
    /// properties their const-ness is intrinsic to the expression type, but for
1005
    /// other expressions like binary operations (addition, ...) their
1006
    /// const-ness depends in turn on the const-ness of their sub-expressions
1007
    /// (left and right operands), which requires a [`Module`] to be retrieved
1008
    /// and evaluated.
1009
    ///
1010
    /// # Example
1011
    ///
1012
    /// ```
1013
    /// # use bevy_hanabi::*;
1014
    /// # let mut module = Module::default();
1015
    /// // Literals are always constant by definition.
1016
    /// assert!(Expr::Literal(LiteralExpr::new(1.)).is_const(&module));
1017
    ///
1018
    /// // Properties and attributes are never constant, since they're by definition used
1019
    /// // to provide runtime customization.
1020
    /// let prop = module.add_property("my_property", 3.0.into());
1021
    /// assert!(!Expr::Property(PropertyExpr::new(prop)).is_const(&module));
1022
    /// assert!(!Expr::Attribute(AttributeExpr::new(Attribute::POSITION)).is_const(&module));
1023
    /// ```
1024
    pub fn is_const(&self, module: &Module) -> bool {
×
1025
        match self {
×
1026
            Expr::BuiltIn(expr) => expr.is_const(),
×
1027
            Expr::Literal(expr) => expr.is_const(),
×
1028
            Expr::Property(expr) => expr.is_const(),
×
1029
            Expr::Attribute(expr) => expr.is_const(),
×
1030
            Expr::ParentAttribute(expr) => expr.is_const(),
×
1031
            Expr::Unary { expr, .. } => module.is_const(*expr),
×
1032
            Expr::Binary { left, right, .. } => module.is_const(*left) && module.is_const(*right),
×
1033
            Expr::Ternary {
1034
                first,
×
1035
                second,
×
1036
                third,
×
1037
                ..
1038
            } => module.is_const(*first) && module.is_const(*second) && module.is_const(*third),
×
1039
            Expr::Cast(expr) => module.is_const(expr.inner),
×
1040
            Expr::TextureSample(_) => false,
×
1041
        }
1042
    }
1043

1044
    /// Has the expression any side-effect?
1045
    ///
1046
    /// Expressions with side-effect need to be stored into temporary variables
1047
    /// when the shader code is emitted, so that the side effect is only applied
1048
    /// once when the expression is reused in multiple locations.
1049
    pub fn has_side_effect(&self, _: &Module) -> bool {
40✔
1050
        match self {
40✔
1051
            Expr::BuiltIn(expr) => expr.has_side_effect(),
×
1052
            Expr::Literal(_) => false,
×
1053
            Expr::Property(_) => false,
×
1054
            Expr::Attribute(_) => false,
×
1055
            Expr::ParentAttribute(_) => false,
×
1056
            Expr::Unary { .. } => false,
×
1057
            Expr::Binary { op, .. } => {
40✔
1058
                *op == BinaryOperator::UniformRand || *op == BinaryOperator::NormalRand
80✔
1059
            }
1060
            Expr::Ternary { .. } => false,
×
1061
            Expr::Cast(_) => false,
×
1062
            Expr::TextureSample(_) => false,
×
1063
        }
1064
    }
1065

1066
    /// The type of the value produced by the expression.
1067
    ///
1068
    /// If the type is variable and depends on the runtime evaluation context,
1069
    /// this returns `None`. In that case the type needs to be obtained by
1070
    /// evaluating the expression with [`eval()`].
1071
    ///
1072
    /// # Example
1073
    ///
1074
    /// ```
1075
    /// # use bevy_hanabi::*;
1076
    /// // Literal expressions always have a constant, build-time value type.
1077
    /// let expr = Expr::Literal(LiteralExpr::new(1.));
1078
    /// assert_eq!(
1079
    ///     expr.value_type(),
1080
    ///     Some(ValueType::Scalar(ScalarType::Float))
1081
    /// );
1082
    /// ```
1083
    ///
1084
    /// [`eval()`]: crate::graph::Expr::eval
1085
    pub fn value_type(&self) -> Option<ValueType> {
25✔
1086
        match self {
25✔
1087
            Expr::BuiltIn(expr) => Some(expr.value_type()),
×
1088
            Expr::Literal(expr) => Some(expr.value_type()),
42✔
1089
            Expr::Property(_) => None,
1✔
1090
            Expr::Attribute(expr) => Some(expr.value_type()),
6✔
1091
            Expr::ParentAttribute(expr) => Some(expr.value_type()),
×
1092
            Expr::Unary { .. } => None,
×
1093
            Expr::Binary { .. } => None,
×
1094
            Expr::Ternary { .. } => None,
×
1095
            Expr::Cast(expr) => Some(expr.value_type()),
×
1096
            Expr::TextureSample(expr) => Some(expr.value_type()),
×
1097
        }
1098
    }
1099

1100
    /// Evaluate the expression in the given context.
1101
    ///
1102
    /// Evaluate the full expression as part of the given evaluation context,
1103
    /// returning the WGSL string representation of the expression on success.
1104
    ///
1105
    /// The evaluation context is used to resolve some quantities related to the
1106
    /// effect asset, like its properties. It also holds the [`Module`] that the
1107
    /// expression is part of, to allow resolving sub-expressions of operators.
1108
    ///
1109
    /// # Example
1110
    ///
1111
    /// ```
1112
    /// # use bevy_hanabi::*;
1113
    /// let mut module = Module::default();
1114
    /// # let pl = PropertyLayout::empty();
1115
    /// # let pal = ParticleLayout::default();
1116
    /// # let mut context = ShaderWriter::new(ModifierContext::Update, &pl, &pal);
1117
    /// let handle = module.lit(1.);
1118
    /// let expr = module.get(handle).unwrap();
1119
    /// assert_eq!(Ok("1.".to_string()), expr.eval(&module, &mut context));
1120
    /// ```
1121
    pub fn eval(
257✔
1122
        &self,
1123
        module: &Module,
1124
        context: &mut dyn EvalContext,
1125
    ) -> Result<String, ExprError> {
1126
        match self {
257✔
1127
            Expr::BuiltIn(expr) => expr.eval(context),
34✔
1128
            Expr::Literal(expr) => expr.eval(context),
416✔
1129
            Expr::Property(expr) => expr.eval(module, context),
10✔
1130
            Expr::Attribute(expr) => expr.eval(context, false),
120✔
1131
            Expr::ParentAttribute(expr) => expr.eval(context, true),
×
1132
            Expr::Unary { op, expr } => {
76✔
1133
                // Recursively evaluate child expressions throught the context to ensure caching
1134
                let expr = context.eval(module, *expr)?;
190✔
1135

1136
                // if expr.value_type() != self.value_type() {
1137
                //     return Err(ExprError::TypeError(format!(
1138
                //         "Cannot apply normalize() function to non-vector expression: {}",
1139
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1140
                //     )));
1141
                // }
1142

1143
                Ok(if op.is_functional() {
1144
                    format!("{}({})", op.to_wgsl_string(), expr)
102✔
1145
                } else {
1146
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1147
                })
1148
            }
1149
            Expr::Binary { op, left, right } => {
120✔
1150
                // Recursively evaluate child expressions throught the context to ensure caching
1151
                let compiled_left = context.eval(module, *left)?;
200✔
1152
                let compiled_right = context.eval(module, *right)?;
40✔
1153

1154
                // if !self.input.value_type().is_vector() {
1155
                //     return Err(ExprError::TypeError(format!(
1156
                //         "Cannot apply normalize() function to non-vector expression: {}",
1157
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1158
                //     )));
1159
                // }
1160

1161
                let body = if op.is_functional() {
40✔
1162
                    if op.needs_type_suffix() {
26✔
1163
                        let lhs_type = module.get(*left).and_then(|arg| arg.value_type());
×
1164
                        let rhs_type = module.get(*right).and_then(|arg| arg.value_type());
×
1165
                        if lhs_type.is_none() || rhs_type.is_none() {
×
1166
                            return Err(ExprError::TypeError(
×
1167
                                "Can't determine the type of the operand".to_string(),
×
1168
                            ));
1169
                        }
1170
                        if lhs_type != rhs_type {
1171
                            return Err(ExprError::TypeError("Mismatched types".to_string()));
×
1172
                        }
1173
                        let value_type = lhs_type.unwrap();
1174
                        let suffix = match value_type {
×
1175
                            ValueType::Scalar(ScalarType::Float) => "f",
×
1176
                            ValueType::Vector(vector_type)
×
1177
                                if vector_type.elem_type() == ScalarType::Float =>
×
1178
                            {
1179
                                match vector_type.count() {
×
1180
                                    2 => "vec2",
×
1181
                                    3 => "vec3",
×
1182
                                    4 => "vec4",
×
1183
                                    _ => unreachable!(),
1184
                                }
1185
                            }
1186
                            _ => {
1187
                                // Add more types here as needed.
1188
                                return Err(ExprError::TypeError("Unsupported type".to_string()));
×
1189
                            }
1190
                        };
1191

1192
                        Ok(format!(
1193
                            "{}_{}({}, {})",
1194
                            op.to_wgsl_string(),
1195
                            suffix,
1196
                            compiled_left,
1197
                            compiled_right
1198
                        ))
1199
                    } else {
1200
                        Ok(format!(
13✔
1201
                            "{}({}, {})",
13✔
1202
                            op.to_wgsl_string(),
13✔
1203
                            compiled_left,
13✔
1204
                            compiled_right
13✔
1205
                        ))
1206
                    }
1207
                } else {
1208
                    Ok(format!(
27✔
1209
                        "({}) {} ({})",
27✔
1210
                        compiled_left,
27✔
1211
                        op.to_wgsl_string(),
27✔
1212
                        compiled_right
27✔
1213
                    ))
1214
                };
1215

1216
                body.map(|body| {
40✔
1217
                    check_side_effects_and_create_local_if_needed(
40✔
1218
                        context,
40✔
1219
                        body,
40✔
1220
                        self.has_side_effect(module),
120✔
1221
                    )
1222
                })
1223
            }
1224
            Expr::Ternary {
1225
                op,
5✔
1226
                first,
5✔
1227
                second,
5✔
1228
                third,
5✔
1229
            } => {
1230
                // Recursively evaluate child expressions throught the context to ensure caching
1231
                let first = context.eval(module, *first)?;
25✔
1232
                let second = context.eval(module, *second)?;
5✔
1233
                let third = context.eval(module, *third)?;
5✔
1234

1235
                // if !self.input.value_type().is_vector() {
1236
                //     return Err(ExprError::TypeError(format!(
1237
                //         "Cannot apply normalize() function to non-vector expression: {}",
1238
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1239
                //     )));
1240
                // }
1241

1242
                Ok(format!(
1243
                    "{}({}, {}, {})",
1244
                    op.to_wgsl_string(),
1245
                    first,
1246
                    second,
1247
                    third
1248
                ))
1249
            }
1250
            Expr::Cast(expr) => {
4✔
1251
                // Recursively evaluate child expressions throught the context to ensure caching
1252
                let inner = context.eval(module, expr.inner)?;
20✔
1253

1254
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
1255
            }
1256
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1257
        }
1258
    }
1259
}
1260

1261
/// A literal constant expression like `3.0` or `vec3<f32>(1.0, 2.0, 3.0)`.
1262
///
1263
/// Literal expression are compile-time constants. They are always constant
1264
/// ([`is_const()`] is `true`) and have a value type equal to the type of the
1265
/// constant itself.
1266
///
1267
/// [`is_const()`]: LiteralExpr::is_const
1268
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
1269
#[serde(transparent)]
1270
pub struct LiteralExpr {
1271
    /// The literal value of this expression.
1272
    pub value: Value,
1273
}
1274

1275
impl LiteralExpr {
1276
    /// Create a new literal expression from a [`Value`].
1277
    pub fn new<V>(value: V) -> Self
340✔
1278
    where
1279
        Value: From<V>,
1280
    {
1281
        Self {
1282
            value: value.into(),
340✔
1283
        }
1284
    }
1285

1286
    /// Is the expression resulting in a compile-time constant which can be
1287
    /// hard-coded into a shader's code?
1288
    pub fn is_const(&self) -> bool {
×
1289
        true
×
1290
    }
1291

1292
    /// Get the value type of the expression.
1293
    pub fn value_type(&self) -> ValueType {
21✔
1294
        self.value.value_type()
42✔
1295
    }
1296

1297
    /// Evaluate the expression in the given context.
1298
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
104✔
1299
        Ok(self.value.to_wgsl_string())
104✔
1300
    }
1301
}
1302

1303
impl ToWgslString for LiteralExpr {
1304
    fn to_wgsl_string(&self) -> String {
×
1305
        self.value.to_wgsl_string()
×
1306
    }
1307
}
1308

1309
impl From<&Value> for LiteralExpr {
1310
    fn from(value: &Value) -> Self {
×
1311
        Self { value: *value }
×
1312
    }
1313
}
1314

1315
impl<T: Into<Value>> From<T> for LiteralExpr {
1316
    fn from(value: T) -> Self {
×
1317
        Self {
1318
            value: value.into(),
×
1319
        }
1320
    }
1321
}
1322

1323
/// Expression representing the value of an attribute of a particle.
1324
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1325
pub struct AttributeExpr {
1326
    /// The attribute this expression represents.
1327
    ///
1328
    /// The expression evaluates to the value of this attribute at the time of
1329
    /// evaluation.
1330
    pub attr: Attribute,
1331
}
1332

1333
impl AttributeExpr {
1334
    /// Create a new attribute expression.
1335
    #[inline]
1336
    pub fn new(attr: Attribute) -> Self {
32✔
1337
        Self { attr }
1338
    }
1339

1340
    /// Is the expression resulting in a compile-time constant which can be
1341
    /// hard-coded into a shader's code?
1342
    pub fn is_const(&self) -> bool {
×
1343
        false
×
1344
    }
1345

1346
    /// Get the value type of the expression.
1347
    pub fn value_type(&self) -> ValueType {
3✔
1348
        self.attr.value_type()
6✔
1349
    }
1350

1351
    /// Evaluate the expression in the given context.
1352
    pub fn eval(&self, context: &dyn EvalContext, parent: bool) -> Result<String, ExprError> {
30✔
1353
        if self.attr == Attribute::ID {
30✔
1354
            // Pseudo-attribute, not stored in the particle buffer
1355
            Ok(if parent {
×
1356
                "parent_particle_index"
×
1357
            } else {
1358
                "particle_index"
×
1359
            }
1360
            .to_string())
×
1361
        } else if self.attr == Attribute::PARTICLE_COUNTER {
30✔
1362
            // Pseudo-attribute, not stored in the particle buffer
1363
            Ok("particle_counter".to_string())
×
1364
        } else {
1365
            let owner = if parent {
30✔
1366
                "parent_particle"
×
1367
            } else {
1368
                "particle"
30✔
1369
            };
1370
            if context.is_attribute_pointer() {
1371
                Ok(format!("(*{}).{}", owner, self.attr.name()))
4✔
1372
            } else {
1373
                Ok(format!("{}.{}", owner, self.attr.name()))
28✔
1374
            }
1375
        }
1376
    }
1377
}
1378

1379
impl ToWgslString for AttributeExpr {
1380
    fn to_wgsl_string(&self) -> String {
×
1381
        format!("particle.{}", self.attr.name())
×
1382
    }
1383
}
1384

1385
impl From<Attribute> for AttributeExpr {
1386
    fn from(value: Attribute) -> Self {
×
1387
        AttributeExpr::new(value)
×
1388
    }
1389
}
1390

1391
/// Expression representing the value of a property of an effect.
1392
///
1393
/// A property expression represents the value of the property at the time the
1394
/// expression appears. In shader, the expression yields a read from the
1395
/// property memory location.
1396
///
1397
/// To create a property to reference with an expression, use
1398
/// [`Module::add_property()`].
1399
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1400
#[repr(transparent)]
1401
#[serde(transparent)]
1402
pub struct PropertyExpr {
1403
    /// The property this expression represents.
1404
    ///
1405
    /// The expression evaluates to the value of this property at the time of
1406
    /// evaluation.
1407
    pub property: PropertyHandle,
1408
}
1409

1410
impl PropertyExpr {
1411
    /// Create a new property expression.
1412
    #[inline]
1413
    pub fn new(property: PropertyHandle) -> Self {
4✔
1414
        Self { property }
1415
    }
1416

1417
    /// Is the expression resulting in a compile-time constant which can be
1418
    /// hard-coded into a shader's code?
1419
    pub fn is_const(&self) -> bool {
×
1420
        false
×
1421
    }
1422

1423
    /// Evaluate the expression in the given context.
1424
    pub fn eval(&self, module: &Module, context: &dyn EvalContext) -> Result<String, ExprError> {
2✔
1425
        let prop = module
4✔
1426
            .get_property(self.property)
4✔
1427
            .ok_or(ExprError::PropertyError(format!(
4✔
1428
                "Unknown property handle {:?} in evaluation module.",
2✔
1429
                self.property
2✔
1430
            )))?;
1431
        if !context.property_layout().contains(prop.name()) {
1432
            return Err(ExprError::PropertyError(format!(
×
1433
                "Unknown property '{}' in evaluation layout.",
×
1434
                prop.name()
×
1435
            )));
1436
        }
1437

1438
        Ok(prop.to_wgsl_string())
2✔
1439
    }
1440
}
1441

1442
/// Expression to cast an expression to another type.
1443
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1444
pub struct CastExpr {
1445
    /// The operand expression to cast.
1446
    pub inner: ExprHandle,
1447
    /// The target type to cast to.
1448
    pub target: ValueType,
1449
}
1450

1451
impl CastExpr {
1452
    /// Create a new cast expression.
1453
    #[inline]
1454
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1455
        Self {
1456
            inner,
1457
            target: target.into(),
12✔
1458
        }
1459
    }
1460

1461
    /// Get the value type of the expression.
1462
    ///
1463
    /// This is the target type the cast converts to.
1464
    pub fn value_type(&self) -> ValueType {
3✔
1465
        self.target
3✔
1466
    }
1467

1468
    /// Try to evaluate if the cast expression is valid.
1469
    ///
1470
    /// The evaluation fails if the value type of the operand cannot be
1471
    /// determined. In that case, the function returns `None`. This doesn't mean
1472
    /// the cast expression is invalid, but rather that we cannot currently
1473
    /// evaluate it, as it likely depends on the runtime context in which it's
1474
    /// used.
1475
    ///
1476
    /// Valid cast expressions are:
1477
    /// - scalar to scalar
1478
    /// - scalar to vector
1479
    /// - vector to vector
1480
    /// - matrix to matrix
1481
    ///
1482
    /// # Returns
1483
    ///
1484
    /// - `Some(is_valid)` if the evaluation was successful in determining
1485
    ///   whether the expression is valid or not.
1486
    /// - `None` if the expression couldn't be evaluated, and so couldn't be
1487
    ///   validated. This generally happens when the inner expression has a
1488
    ///   value type unknown statically (depends on runtime context), which
1489
    ///   prevents evaluating whether the cast expression is valid.
1490
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
12✔
1491
        let Some(inner) = module.get(self.inner) else {
36✔
1492
            return Some(false);
×
1493
        };
1494
        if let Some(inner_type) = inner.value_type() {
11✔
1495
            match self.target {
1496
                ValueType::Scalar(_) => {
1497
                    // scalar -> scalar only
1498
                    Some(matches!(inner_type, ValueType::Scalar(_)))
8✔
1499
                }
1500
                ValueType::Vector(_) => {
1501
                    // {scalar, vector} -> vector
1502
                    Some(!matches!(inner_type, ValueType::Matrix(_)))
7✔
1503
                }
1504
                ValueType::Matrix(_) => {
1505
                    // matrix -> matrix only
1506
                    Some(matches!(inner_type, ValueType::Matrix(_)))
4✔
1507
                }
1508
            }
1509
        } else {
1510
            None
1✔
1511
        }
1512
    }
1513
}
1514

1515
/// Expression to sample a texture from the effect's material.
1516
///
1517
/// This currently supports only 4-component textures sampled with [the WGSL
1518
/// `textureSample()` function], that is all textures which return a `vec4<f32>`
1519
/// when sampled. This is the case of most color textures, including
1520
/// single-channel (e.g. red) textures which return zero for missing components,
1521
/// but excludes depth textures.
1522
///
1523
/// [the WGSL `textureSample()` function]: https://www.w3.org/TR/WGSL/#texturesample
1524
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1525
pub struct TextureSampleExpr {
1526
    /// The index of the image to sample. This is the texture slot defined in
1527
    /// the [`Module`]. The texture bound to the slot is defined in the
1528
    /// [`EffectMaterial`] component.
1529
    ///
1530
    /// [`EffectMaterial`]: crate::EffectMaterial
1531
    pub image: ExprHandle,
1532
    /// The coordinates to sample at.
1533
    pub coordinates: ExprHandle,
1534
}
1535

1536
impl TextureSampleExpr {
1537
    /// Create a new texture sample expression.
1538
    #[inline]
1539
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1540
        Self { image, coordinates }
1541
    }
1542

1543
    /// Get the value type of the expression.
1544
    pub fn value_type(&self) -> ValueType {
×
1545
        // FIXME - depth textures return a single f32 when sampled
1546
        ValueType::Vector(VectorType::VEC4F)
×
1547
    }
1548

1549
    /// Try to evaluate if the texture sample expression is valid.
1550
    ///
1551
    /// This only checks that the expressions exist in the module.
1552
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
×
1553
        let Some(_image) = module.get(self.image) else {
×
1554
            return Some(false);
×
1555
        };
1556
        let Some(_coordinates) = module.get(self.coordinates) else {
×
1557
            return Some(false);
×
1558
        };
1559
        Some(true)
×
1560
    }
1561

1562
    /// Evaluate the expression in the given context.
1563
    pub fn eval(
×
1564
        &self,
1565
        module: &Module,
1566
        context: &mut dyn EvalContext,
1567
    ) -> Result<String, ExprError> {
1568
        let image = module.try_get(self.image)?;
×
1569
        let image = image.eval(module, context)?;
×
1570
        let coordinates = module.try_get(self.coordinates)?;
×
1571
        let coordinates = coordinates.eval(module, context)?;
×
1572
        Ok(format!(
1573
            "textureSample(material_texture_{image}, material_sampler_{image}, {coordinates})",
1574
        ))
1575
    }
1576
}
1577

1578
/// Built-in operators.
1579
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1580
pub enum BuiltInOperator {
1581
    /// Current effect system simulation time since startup, in seconds.
1582
    ///
1583
    /// This is based on the
1584
    /// [`Time<EffectSimulation>`](crate::time::EffectSimulation) clock.
1585
    ///
1586
    /// Type: `f32`
1587
    Time,
1588
    /// Delta time, in seconds, since last effect system update.
1589
    ///
1590
    /// Type: `f32`
1591
    DeltaTime,
1592
    /// Current virtual time since startup, in seconds.
1593
    ///
1594
    /// This is based on the [`Time<Virtual>`](bevy::time::Virtual) clock.
1595
    ///
1596
    /// Type: `f32`
1597
    VirtualTime,
1598
    /// Virtual delta time, in seconds, since last effect system update.
1599
    ///
1600
    /// Type: `f32`
1601
    VirtualDeltaTime,
1602
    /// Current real time since startup, in seconds.
1603
    ///
1604
    /// This is based on the [`Time<Time>`](bevy::time::Real) clock.
1605
    ///
1606
    /// Type: `f32`
1607
    RealTime,
1608
    /// Real delta time, in seconds, since last effect system update.
1609
    ///
1610
    /// Type: `f32`
1611
    RealDeltaTime,
1612
    /// Random unit value of the given type.
1613
    ///
1614
    /// The type can be any scalar or vector type. Matrix types are not
1615
    /// supported. The random values generated are uniformly distributed in
1616
    /// `[0:1]`. For vectors, each component is sampled separately.
1617
    ///
1618
    /// The random number generator is from [the PCG family] of PRNGs, and is
1619
    /// implemented directly inside the shader, and running on the GPU
1620
    /// exclusively. It's seeded by the [`SpawnerSettings`].
1621
    ///
1622
    /// Type: Same as its [`ValueType`].
1623
    ///
1624
    /// [the PCG family]: https://www.pcg-random.org/
1625
    /// [`SpawnerSettings`]: crate::SpawnerSettings
1626
    Rand(ValueType),
1627
    /// Value of the alpha cutoff for alpha masking.
1628
    ///
1629
    /// This value is only available in the render context. It represents the
1630
    /// current threshold, generally in \[0:1\], which the particle's fragment
1631
    /// alpha value will be compared against to determine alpha masking.
1632
    ///
1633
    /// The value is initalized at the beginning of the fragment shader to the
1634
    /// expression stored in [`AlphaMode::Mask`].
1635
    ///
1636
    /// Type: `f32`
1637
    ///
1638
    /// [`AlphaMode::Mask`]: crate::AlphaMode::Mask
1639
    AlphaCutoff,
1640
    /// Alive flag for the particle.
1641
    ///
1642
    /// The alive flag is initialized at the beginning of the update pass:
1643
    /// - If the particle has both the [`Attribute::AGE`] and
1644
    ///   [`Attribute::LIFETIME`], then the initial value at the beginning of
1645
    ///   the update pass is `age < lifetime`.
1646
    /// - Otherwise, the initial value is `true`.
1647
    ///
1648
    /// At the end of the update pass, if the particle has both the
1649
    /// [`Attribute::AGE`] and [`Attribute::LIFETIME`], then the flag is
1650
    /// re-evaluated as:
1651
    ///
1652
    /// ```wgsl
1653
    /// is_alive = is_alive && (particle.age < particle.lifetime);
1654
    /// ```
1655
    ///
1656
    /// If the flag is `false` after that, the particle is considered dead and
1657
    /// it's deallocated.
1658
    ///
1659
    /// This flag is only available in the update pass. Attempting to use it
1660
    /// inside either the init or render passes will generate an invalid shader.
1661
    ///
1662
    /// Type: `bool`
1663
    IsAlive,
1664
}
1665

1666
impl BuiltInOperator {
1667
    /// Get the operator name.
1668
    pub fn name(&self) -> &str {
49✔
1669
        match self {
49✔
1670
            BuiltInOperator::Time => "time",
6✔
1671
            BuiltInOperator::DeltaTime => "delta_time",
13✔
1672
            BuiltInOperator::VirtualTime => "virtual_time",
2✔
1673
            BuiltInOperator::VirtualDeltaTime => "virtual_delta_time",
2✔
1674
            BuiltInOperator::RealTime => "real_time",
2✔
1675
            BuiltInOperator::RealDeltaTime => "real_delta_time",
2✔
1676
            BuiltInOperator::Rand(value_type) => match value_type {
44✔
1677
                ValueType::Scalar(s) => match s {
20✔
1678
                    ScalarType::Bool => "brand",
1✔
1679
                    ScalarType::Float => "frand",
7✔
1680
                    ScalarType::Int => "irand",
1✔
1681
                    ScalarType::Uint => "urand",
1✔
1682
                },
1683
                ValueType::Vector(vector_type) => {
12✔
1684
                    match (vector_type.elem_type(), vector_type.count()) {
36✔
1685
                        (ScalarType::Bool, 2) => "brand2",
1✔
1686
                        (ScalarType::Bool, 3) => "brand3",
1✔
1687
                        (ScalarType::Bool, 4) => "brand4",
1✔
1688
                        (ScalarType::Float, 2) => "frand2",
1✔
1689
                        (ScalarType::Float, 3) => "frand3",
1✔
1690
                        (ScalarType::Float, 4) => "frand4",
1✔
1691
                        (ScalarType::Int, 2) => "irand2",
1✔
1692
                        (ScalarType::Int, 3) => "irand3",
1✔
1693
                        (ScalarType::Int, 4) => "irand4",
1✔
1694
                        (ScalarType::Uint, 2) => "urand2",
1✔
1695
                        (ScalarType::Uint, 3) => "urand3",
1✔
1696
                        (ScalarType::Uint, 4) => "urand4",
1✔
1697
                        _ => panic!("Invalid vector type {:?}", vector_type),
×
1698
                    }
1699
                }
1700
                ValueType::Matrix(_) => panic!("Invalid BuiltInOperator::Rand(ValueType::Matrix)."),
×
1701
            },
1702
            BuiltInOperator::AlphaCutoff => "alpha_cutoff",
×
1703
            BuiltInOperator::IsAlive => "is_alive",
×
1704
        }
1705
    }
1706

1707
    /// Get the type of the value of a built-in operator.
1708
    pub fn value_type(&self) -> ValueType {
4✔
1709
        match self {
4✔
1710
            BuiltInOperator::Time => ValueType::Scalar(ScalarType::Float),
2✔
1711
            BuiltInOperator::DeltaTime => ValueType::Scalar(ScalarType::Float),
2✔
1712
            BuiltInOperator::VirtualTime => ValueType::Scalar(ScalarType::Float),
×
1713
            BuiltInOperator::VirtualDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1714
            BuiltInOperator::RealTime => ValueType::Scalar(ScalarType::Float),
×
1715
            BuiltInOperator::RealDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1716
            BuiltInOperator::Rand(value_type) => *value_type,
×
1717
            BuiltInOperator::AlphaCutoff => ValueType::Scalar(ScalarType::Float),
×
1718
            BuiltInOperator::IsAlive => ValueType::Scalar(ScalarType::Bool),
×
1719
        }
1720
    }
1721

1722
    // /// Evaluate the result of the operator as an expression.
1723
    // pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
1724
    //     match self {
1725
    //         BuiltInOperator::Time => Value::Scalar(Scal)
1726
    //     }
1727
    // }
1728
}
1729

1730
impl ToWgslString for BuiltInOperator {
1731
    fn to_wgsl_string(&self) -> String {
37✔
1732
        match self {
37✔
1733
            BuiltInOperator::Rand(_) => format!("{}()", self.name()),
22✔
1734
            BuiltInOperator::IsAlive => "is_alive".to_string(),
2✔
1735
            _ => format!("sim_params.{}", self.name()),
42✔
1736
        }
1737
    }
1738
}
1739

1740
/// Expression for getting built-in quantities related to the effect system.
1741
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1742
pub struct BuiltInExpr {
1743
    /// The built-in operator this expression represents.
1744
    ///
1745
    /// The expression evaluates to the value of this built-in operator at the
1746
    /// time of evaluation.
1747
    pub operator: BuiltInOperator,
1748
}
1749

1750
impl BuiltInExpr {
1751
    /// Create a new built-in operator expression.
1752
    ///
1753
    /// # Panics
1754
    ///
1755
    /// Panics on invalid [`BuiltInOperator`], like `Rand(MatrixType)`. See
1756
    /// each [`BuiltInOperator`] variant for more details.
1757
    #[inline]
1758
    pub fn new(operator: BuiltInOperator) -> Self {
33✔
1759
        if let BuiltInOperator::Rand(value_type) = operator {
51✔
1760
            assert!(!matches!(value_type, ValueType::Matrix(_)));
18✔
1761
        }
1762
        Self { operator }
1763
    }
1764

1765
    /// Is the expression resulting in a compile-time constant?
1766
    ///
1767
    /// Constant expressions can be hard-coded into a shader's code, making them
1768
    /// more efficient and open to shader compiler optimizing.
1769
    pub fn is_const(&self) -> bool {
×
1770
        false
×
1771
    }
1772

1773
    /// Has the expression any side-effect?
1774
    ///
1775
    /// Expressions with side-effect need to be stored into temporary variables
1776
    /// when the shader code is emitted, so that the side effect is only applied
1777
    /// once when the expression is reused in multiple locations.
1778
    pub fn has_side_effect(&self) -> bool {
37✔
1779
        matches!(self.operator, BuiltInOperator::Rand(_))
52✔
1780
    }
1781

1782
    /// Get the value type of the expression.
1783
    ///
1784
    /// The value type of the expression is the type of the value(s) that an
1785
    /// expression produces.
1786
    pub fn value_type(&self) -> ValueType {
×
1787
        self.operator.value_type()
×
1788
    }
1789

1790
    /// Evaluate the expression in the given context.
1791
    pub fn eval(&self, context: &mut dyn EvalContext) -> Result<String, ExprError> {
37✔
1792
        Ok(check_side_effects_and_create_local_if_needed(
74✔
1793
            context,
74✔
1794
            self.to_wgsl_string(),
111✔
1795
            self.has_side_effect(),
37✔
1796
        ))
1797
    }
1798
}
1799

1800
impl ToWgslString for BuiltInExpr {
1801
    fn to_wgsl_string(&self) -> String {
37✔
1802
        self.operator.to_wgsl_string()
74✔
1803
    }
1804
}
1805

1806
/// Creates a local variable if necessary to avoid evaluating side-effecting
1807
/// expressions multiple times.
1808
///
1809
/// If `has_side_effect` is true, this function creates a local variable within
1810
/// the [`EvalContext`] and stores the `compiled_code` there. Otherwise, it
1811
/// simply returns `compiled_code` unchanged.
1812
fn check_side_effects_and_create_local_if_needed(
77✔
1813
    context: &mut dyn EvalContext,
1814
    compiled_code: String,
1815
    has_side_effect: bool,
1816
) -> String {
1817
    if has_side_effect {
77✔
1818
        let var_name = context.make_local_var();
66✔
1819
        context.push_stmt(&format!("let {} = {};", var_name, compiled_code));
66✔
1820
        var_name
22✔
1821
    } else {
1822
        compiled_code
55✔
1823
    }
1824
}
1825

1826
/// Unary operator.
1827
///
1828
/// Operator applied to a single operand to produce another value. The type of
1829
/// the operand and the result are not necessarily the same. Valid operand types
1830
/// depend on the operator itself.
1831
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1832
pub enum UnaryOperator {
1833
    /// Absolute value operator.
1834
    ///
1835
    /// Return the absolute value of the operand, component-wise for vectors.
1836
    /// Only valid for numeric operands.
1837
    Abs,
1838

1839
    /// Inverse cosine operator.
1840
    ///
1841
    /// Return the inverse cosine of the operand, component-wise for vectors.
1842
    /// Only valid for floating-point operands.
1843
    Acos,
1844

1845
    /// Inverse sine operator.
1846
    ///
1847
    /// Return the inverse sine of the operand, component-wise for vectors.
1848
    /// Only valid for floating-point operands.
1849
    Asin,
1850

1851
    /// Inverse tangent operator.
1852
    ///
1853
    /// Return the inverse tangent of the operand, component-wise for vectors.
1854
    /// Only valid for floating-point operands.
1855
    Atan,
1856

1857
    /// Logical ALL operator for bool vectors.
1858
    ///
1859
    /// Return `true` if all the components of the bool vector operand are
1860
    /// `true`. Invalid for any other type of operand.
1861
    All,
1862

1863
    /// Logical ANY operator for bool vectors.
1864
    ///
1865
    /// Return `true` if any component of the bool vector operand is `true`.
1866
    /// Invalid for any other type of operand.
1867
    Any,
1868

1869
    /// Ceiling operator.
1870
    ///
1871
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1872
    /// `x` is the operand which the operator applies to.
1873
    Ceil,
1874

1875
    /// Cosine operator.
1876
    Cos,
1877

1878
    /// Natural exponent operator.
1879
    ///
1880
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1881
    /// for vectors.
1882
    Exp,
1883

1884
    /// Base-2 exponent operator.
1885
    ///
1886
    /// Return two raised to the power of the operand (`2^x`), component-wise
1887
    /// for vectors.
1888
    Exp2,
1889

1890
    /// Floor operator.
1891
    ///
1892
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1893
    /// `x` is the operand which the operator applies to.
1894
    Floor,
1895

1896
    /// Fractional part operator.
1897
    ///
1898
    /// Return the fractional part of the operand, which is equal to `x -
1899
    /// floor(x)`, component-wise for vectors.
1900
    Fract,
1901

1902
    /// Inverse square root operator.
1903
    ///
1904
    /// Return the inverse square root of the floating-point operand (`1.0 /
1905
    /// sqrt(x)`), component-wise for vectors.
1906
    InvSqrt,
1907

1908
    /// Length operator.
1909
    ///
1910
    /// Return the length of a floating point scalar or vector. The "length" of
1911
    /// a scalar is taken as its absolute value. The length of a vector is the
1912
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1913
    /// squared components).
1914
    ///
1915
    /// The output is always a floating point scalar.
1916
    Length,
1917

1918
    /// Natural logarithm operator.
1919
    ///
1920
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1921
    /// for vectors.
1922
    Log,
1923

1924
    /// Base-2 logarithm operator.
1925
    ///
1926
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1927
    /// for vectors.
1928
    Log2,
1929

1930
    /// Vector normalizing operator.
1931
    ///
1932
    /// Normalize the given numeric vector. Only valid for numeric vector
1933
    /// operands.
1934
    Normalize,
1935

1936
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1937
    ///
1938
    /// Convert the four components of a signed normalized floating point vector
1939
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1940
    /// four values into a single `u32`. Each vector component should be in
1941
    /// `[-1:1]` before packing; values outside this range are clamped.
1942
    Pack4x8snorm,
1943

1944
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1945
    ///
1946
    /// Convert the four components of an unsigned normalized floating point
1947
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1948
    /// those four values into a single `u32`. Each vector component should
1949
    /// be in `[0:1]` before packing; values outside this range are clamped.
1950
    Pack4x8unorm,
1951

1952
    /// Rounding operator.
1953
    ///
1954
    /// Round the given scalar of vector float to the nearest integer, returned
1955
    /// as a float value.
1956
    Round,
1957

1958
    /// Saturate operator.
1959
    ///
1960
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1961
    /// vectors.
1962
    Saturate,
1963

1964
    /// Sign operator.
1965
    ///
1966
    /// Return a value representing the sign of a floating point scalar or
1967
    /// vector input:
1968
    /// - `1.` if the operand is > 0
1969
    /// - `0.` if the operand is = 0
1970
    /// - `-1.` if the operand is < 0
1971
    ///
1972
    /// Applies component-wise for vectors.
1973
    Sign,
1974

1975
    /// Sine operator.
1976
    Sin,
1977

1978
    /// Square root operator.
1979
    ///
1980
    /// Return the square root of the floating-point operand, component-wise for
1981
    /// vectors.
1982
    Sqrt,
1983

1984
    /// Tangent operator.
1985
    Tan,
1986

1987
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1988
    ///
1989
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1990
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1991
    Unpack4x8snorm,
1992

1993
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1994
    ///
1995
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1996
    /// then convert each value to an unsigned normalized `f32` value in
1997
    /// `[0:1]`.
1998
    Unpack4x8unorm,
1999

2000
    /// Get the fourth component of a vector.
2001
    ///
2002
    /// This is only valid for vectors of rank 4.
2003
    W,
2004

2005
    /// Get the first component of a scalar or vector.
2006
    ///
2007
    /// For scalar, return the value itself. For vectors, return the first
2008
    /// component.
2009
    X,
2010

2011
    /// Get the second component of a vector.
2012
    Y,
2013

2014
    /// Get the third component of a vector.
2015
    ///
2016
    /// This is only valid for vectors of rank 3 or more.
2017
    Z,
2018
}
2019

2020
impl UnaryOperator {
2021
    /// Check if a unary operator is called via a functional-style call.
2022
    ///
2023
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
2024
    /// example, while non-functional ones are in the form `inner.op`,
2025
    /// like `v.x` for example. This check is used for formatting the WGSL
2026
    /// code emitted during evaluation of a binary operation expression.
2027
    pub fn is_functional(&self) -> bool {
38✔
2028
        !matches!(
34✔
2029
            *self,
38✔
2030
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
2031
        )
2032
    }
2033
}
2034

2035
impl ToWgslString for UnaryOperator {
2036
    fn to_wgsl_string(&self) -> String {
38✔
2037
        match *self {
38✔
2038
            UnaryOperator::Abs => "abs".to_string(),
5✔
2039
            UnaryOperator::Acos => "acos".to_string(),
2✔
2040
            UnaryOperator::Asin => "asin".to_string(),
2✔
2041
            UnaryOperator::Atan => "atan".to_string(),
2✔
2042
            UnaryOperator::All => "all".to_string(),
2✔
2043
            UnaryOperator::Any => "any".to_string(),
6✔
2044
            UnaryOperator::Ceil => "ceil".to_string(),
2✔
2045
            UnaryOperator::Cos => "cos".to_string(),
2✔
2046
            UnaryOperator::Exp => "exp".to_string(),
2✔
2047
            UnaryOperator::Exp2 => "exp2".to_string(),
2✔
2048
            UnaryOperator::Floor => "floor".to_string(),
2✔
2049
            UnaryOperator::Fract => "fract".to_string(),
2✔
2050
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
2✔
2051
            UnaryOperator::Length => "length".to_string(),
2✔
2052
            UnaryOperator::Log => "log".to_string(),
2✔
2053
            UnaryOperator::Log2 => "log2".to_string(),
2✔
2054
            UnaryOperator::Normalize => "normalize".to_string(),
4✔
2055
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
2✔
2056
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
2✔
2057
            UnaryOperator::Round => "round".to_string(),
2✔
2058
            UnaryOperator::Saturate => "saturate".to_string(),
2✔
2059
            UnaryOperator::Sign => "sign".to_string(),
2✔
2060
            UnaryOperator::Sin => "sin".to_string(),
2✔
2061
            UnaryOperator::Sqrt => "sqrt".to_string(),
2✔
2062
            UnaryOperator::Tan => "tan".to_string(),
2✔
2063
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
2✔
2064
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
2✔
2065
            UnaryOperator::W => "w".to_string(),
2✔
2066
            UnaryOperator::X => "x".to_string(),
2✔
2067
            UnaryOperator::Y => "y".to_string(),
2✔
2068
            UnaryOperator::Z => "z".to_string(),
2✔
2069
        }
2070
    }
2071
}
2072

2073
/// Binary operator.
2074
///
2075
/// Operator applied between two operands, generally denoted "left" and "right".
2076
/// The type of the operands and the result are not necessarily the same. Valid
2077
/// operand types depend on the operator itself.
2078
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2079
pub enum BinaryOperator {
2080
    /// Addition operator.
2081
    ///
2082
    /// Returns the sum of its operands. Only valid for numeric operands.
2083
    Add,
2084

2085
    /// Inverse tangent operator with 2 arguments.
2086
    ///
2087
    /// Returns the arctangent (inverse tangent) of the ratio of the first
2088
    /// argument divided by the second argument.
2089
    Atan2,
2090

2091
    /// Cross product operator.
2092
    ///
2093
    /// Returns the cross product of the left and right operands. Only valid for
2094
    /// vector type operands of size 3. Always produce a vector result of the
2095
    /// same size.
2096
    Cross,
2097

2098
    /// Distance operator.
2099
    ///
2100
    /// Returns the distance between two floating point scalar or vectors, that
2101
    /// is `length(right - left)`.
2102
    Distance,
2103

2104
    /// Division operator.
2105
    ///
2106
    /// Returns the left operand divided by the right operand. Only valid for
2107
    /// numeric operands.
2108
    Div,
2109

2110
    /// Dot product operator.
2111
    ///
2112
    /// Returns the dot product of the left and right operands. Only valid for
2113
    /// vector type operands. Always produce a scalar floating-point result.
2114
    Dot,
2115

2116
    /// Greater-than operator.
2117
    ///
2118
    /// Returns `true` if the left operand is strictly greater than the right
2119
    /// operand. Only valid for numeric types. If the operands are vectors,
2120
    /// they must be of the same rank, and the result is a bool vector of
2121
    /// that rank.
2122
    GreaterThan,
2123

2124
    /// Greater-than-or-equal operator.
2125
    ///
2126
    /// Returns `true` if the left operand is greater than or equal to the right
2127
    /// operand. Only valid for numeric types. If the operands are vectors,
2128
    /// they must be of the same rank, and the result is a bool vector of
2129
    /// that rank.
2130
    GreaterThanOrEqual,
2131

2132
    /// Less-than operator.
2133
    ///
2134
    /// Returns `true` if the left operand is strictly less than the right
2135
    /// operand. Only valid for numeric types. If the operands are vectors,
2136
    /// they must be of the same rank, and the result is a bool vector of
2137
    /// that rank.
2138
    LessThan,
2139

2140
    /// Less-than-or-equal operator.
2141
    ///
2142
    /// Returns `true` if the left operand is less than or equal to the right
2143
    /// operand. Only valid for numeric types. If the operands are vectors,
2144
    /// they must be of the same rank, and the result is a bool vector of
2145
    /// that rank.
2146
    LessThanOrEqual,
2147

2148
    /// Maximum operator.
2149
    ///
2150
    /// Returns the maximum value of its left and right operands. Only valid for
2151
    /// numeric types. If the operands are vectors, they must be of the same
2152
    /// rank, and the result is a vector of that rank and same element
2153
    /// scalar type.
2154
    Max,
2155

2156
    /// Minimum operator.
2157
    ///
2158
    /// Returns the minimum value of its left and right operands. Only valid for
2159
    /// numeric types. If the operands are vectors, they must be of the same
2160
    /// rank, and the result is a vector of that rank and same element
2161
    /// scalar type.
2162
    Min,
2163

2164
    /// Multiply operator.
2165
    ///
2166
    /// Returns the product of its operands. Only valid for numeric operands.
2167
    Mul,
2168

2169
    /// Remainder operator.
2170
    ///
2171
    /// Returns the remainder of the division of the first operand by the
2172
    /// second. Only valid for numeric types. If the operands are vectors,
2173
    /// they must be of the same rank, and the result is a vector of that
2174
    /// rank and same element scalar type.
2175
    Remainder,
2176

2177
    /// Stepping operator.
2178
    ///
2179
    /// Returns `1.0` if the left operand is less than or equal to the right
2180
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
2181
    /// of the same rank, and applied component-wise for vectors.
2182
    Step,
2183

2184
    /// Subtraction operator.
2185
    ///
2186
    /// Returns the difference between its left and right operands. Only valid
2187
    /// for numeric operands.
2188
    Sub,
2189

2190
    /// Uniform random number operator.
2191
    ///
2192
    /// Returns a value generated by a fast non-cryptographically-secure
2193
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2194
    /// are undefined and generally focused around speed. The random value is
2195
    /// uniformly distributed between the left and right operands, which must be
2196
    /// numeric types. If the operands are vectors, they must be of the same
2197
    /// rank, and the result is a vector of that rank and same element
2198
    /// scalar type.
2199
    UniformRand,
2200

2201
    /// Normal distribution random number operator.
2202
    ///
2203
    /// Returns a value generated by a fast non-cryptographically-secure
2204
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2205
    /// are undefined and generally focused around speed. The random value is
2206
    /// normally distributed with mean given by the first operand and standard
2207
    /// deviation by the second, which must be numeric types. If the operands
2208
    /// are vectors, they must be of the same rank, and the result is a vector
2209
    /// of that rank and same element scalar type.
2210
    NormalRand,
2211

2212
    /// Constructor for 2-element vectors.
2213
    ///
2214
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
2215
    /// those two elements `(x, y)`.
2216
    Vec2,
2217

2218
    /// Constructor for a 4-element vector.
2219
    ///
2220
    /// Given a 3-element vector `xyz` and a scalar value `w`, returns the
2221
    /// vector `vec4(xyz, w)`.
2222
    Vec4XyzW,
2223
}
2224

2225
impl BinaryOperator {
2226
    /// Check if a binary operator is called via a functional-style call.
2227
    ///
2228
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
2229
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
2230
    /// like `a + b` for example. This check is used for formatting the WGSL
2231
    /// code emitted during evaluation of a binary operation expression.
2232
    pub fn is_functional(&self) -> bool {
40✔
2233
        match *self {
40✔
2234
            BinaryOperator::Add
2235
            | BinaryOperator::Div
2236
            | BinaryOperator::GreaterThan
2237
            | BinaryOperator::GreaterThanOrEqual
2238
            | BinaryOperator::LessThan
2239
            | BinaryOperator::LessThanOrEqual
2240
            | BinaryOperator::Mul
2241
            | BinaryOperator::Remainder
2242
            | BinaryOperator::Sub => false,
27✔
2243
            BinaryOperator::Atan2
2244
            | BinaryOperator::Cross
2245
            | BinaryOperator::Distance
2246
            | BinaryOperator::Dot
2247
            | BinaryOperator::Max
2248
            | BinaryOperator::Min
2249
            | BinaryOperator::Step
2250
            | BinaryOperator::UniformRand
2251
            | BinaryOperator::NormalRand
2252
            | BinaryOperator::Vec2
2253
            | BinaryOperator::Vec4XyzW => true,
13✔
2254
        }
2255
    }
2256

2257
    /// Check if a binary operator needs a type suffix.
2258
    ///
2259
    /// This is currently just for `rand_uniform`
2260
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2261
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2262
    /// WGSL doesn't support user-defined function overloading, so we need a
2263
    /// suffix to disambiguate the types.
2264
    pub fn needs_type_suffix(&self) -> bool {
13✔
2265
        matches!(
13✔
2266
            *self,
13✔
2267
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2268
        )
2269
    }
2270
}
2271

2272
impl ToWgslString for BinaryOperator {
2273
    fn to_wgsl_string(&self) -> String {
40✔
2274
        match *self {
40✔
2275
            BinaryOperator::Add => "+".to_string(),
5✔
2276
            BinaryOperator::Atan2 => "atan2".to_string(),
2✔
2277
            BinaryOperator::Cross => "cross".to_string(),
2✔
2278
            BinaryOperator::Distance => "distance".to_string(),
2✔
2279
            BinaryOperator::Div => "/".to_string(),
4✔
2280
            BinaryOperator::Dot => "dot".to_string(),
2✔
2281
            BinaryOperator::GreaterThan => ">".to_string(),
6✔
2282
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
2✔
2283
            BinaryOperator::LessThan => "<".to_string(),
2✔
2284
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
2✔
2285
            BinaryOperator::Max => "max".to_string(),
10✔
2286
            BinaryOperator::Min => "min".to_string(),
4✔
2287
            BinaryOperator::Mul => "*".to_string(),
12✔
2288
            BinaryOperator::Remainder => "%".to_string(),
2✔
2289
            BinaryOperator::Step => "step".to_string(),
2✔
2290
            BinaryOperator::Sub => "-".to_string(),
14✔
2291
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
2292
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
2293
            BinaryOperator::Vec2 => "vec2".to_string(),
×
2294
            BinaryOperator::Vec4XyzW => "vec4".to_string(),
2✔
2295
        }
2296
    }
2297
}
2298

2299
/// Ternary operator.
2300
///
2301
/// Operator applied between three operands. The type of the operands and the
2302
/// result are not necessarily the same. Valid operand types depend on the
2303
/// operator itself.
2304
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2305
pub enum TernaryOperator {
2306
    /// Linear blend ("mix") operator.
2307
    ///
2308
    /// Returns the linear blend between the first and second argument, based on
2309
    /// the fraction of the third argument. If the operands are vectors, they
2310
    /// must be of the same rank, and the result is a vector of that rank
2311
    /// and same element scalar type.
2312
    ///
2313
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2314
    /// (1 - t) + y * t`.
2315
    Mix,
2316

2317
    /// Clamp operator.
2318
    ///
2319
    /// Returns the first argument clamped to the range defined by the second
2320
    /// and third arguments. If the operands are vectors, they must be of
2321
    /// the same rank, and the result is a vector of that rank
2322
    /// and same element scalar type.
2323
    ///
2324
    /// The expression `clamp(x, low, high)` is equivalent to `min(max(x, low),
2325
    /// high)`.
2326
    Clamp,
2327

2328
    /// Smooth stepping operator.
2329
    ///
2330
    /// Returns the smooth Hermitian interpolation between the first and second
2331
    /// argument, calculated at the third argument. If the operands are vectors,
2332
    /// they must be of the same rank, and the result is a vector of that
2333
    /// rank and same element scalar type.
2334
    ///
2335
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2336
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2337
    /// represents the fractional position of `x` between `low` and `high`.
2338
    ///
2339
    /// The result is always a floating point scalar in \[0:1\].
2340
    SmoothStep,
2341

2342
    /// Constructor for 3-element vectors.
2343
    ///
2344
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2345
    /// consisting of those three elements `(x, y, z)`.
2346
    Vec3,
2347
}
2348

2349
impl ToWgslString for TernaryOperator {
2350
    fn to_wgsl_string(&self) -> String {
5✔
2351
        match *self {
5✔
2352
            TernaryOperator::Mix => "mix".to_string(),
2✔
2353
            TernaryOperator::Clamp => "clamp".to_string(),
2✔
2354
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
2✔
2355
            TernaryOperator::Vec3 => "vec3".to_string(),
2✔
2356
        }
2357
    }
2358
}
2359

2360
/// Expression writer.
2361
///
2362
/// Utility to write expressions with a simple functional syntax. Expressions
2363
/// created with the writer are gatherned into a [`Module`] which can be
2364
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2365
///
2366
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2367
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2368
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2369
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2370
/// to assign it to the [`EffectAsset`].
2371
///
2372
/// # Example
2373
///
2374
/// ```
2375
/// # use bevy_hanabi::*;
2376
/// # use bevy::prelude::*;
2377
/// // Create a writer
2378
/// let w = ExprWriter::new();
2379
///
2380
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2381
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2382
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2383
///
2384
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2385
/// let expr: ExprHandle = expr.expr();
2386
///
2387
/// // Create a modifier and assign the expression to one of its input(s)
2388
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2389
///
2390
/// // Create an EffectAsset with the modifier and the Module from the writer
2391
/// let effect = EffectAsset::new(1024, SpawnerSettings::rate(32_f32.into()), w.finish())
2392
///     .init(init_modifier);
2393
/// ```
2394
///
2395
/// [`finish()`]: ExprWriter::finish
2396
/// [`EffectAsset`]: crate::EffectAsset
2397
/// [`Modifer`]: crate::Modifier
2398
#[derive(Debug, Default, Clone)]
2399
pub struct ExprWriter {
2400
    module: Rc<RefCell<Module>>,
2401
}
2402

2403
#[allow(dead_code)]
2404
impl ExprWriter {
2405
    /// Create a new writer.
2406
    ///
2407
    /// The writer owns a new [`Module`] internally, and write all expressions
2408
    /// to it. The module can be released to the user with [`finish()`] once
2409
    /// done using the writer.
2410
    ///
2411
    /// [`finish()`]: ExprWriter::finish
2412
    pub fn new() -> Self {
3✔
2413
        Self {
2414
            module: Rc::new(RefCell::new(Module::default())),
6✔
2415
        }
2416
    }
2417

2418
    /// Create a new writer from an existing module.
2419
    ///
2420
    /// This is an advanced use entry point to write expressions into an
2421
    /// existing [`Module`]. In general, users should prefer using
2422
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2423
    /// same [`ExprWriter`] to write all expressions of the same
2424
    /// [`EffectAsset`].
2425
    ///
2426
    /// [`EffectAsset`]: crate::EffectAsset
2427
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2428
        Self { module }
2429
    }
2430

2431
    /// Add a new property.
2432
    ///
2433
    /// See [`Property`] for more details on what effect properties are.
2434
    ///
2435
    /// # Panics
2436
    ///
2437
    /// Panics if a property with the same name already exists.
2438
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2439
        self.module.borrow_mut().add_property(name, default_value)
3✔
2440
    }
2441

2442
    /// Push a new expression into the writer.
2443
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2444
        let expr = {
13✔
2445
            let mut m = self.module.borrow_mut();
26✔
2446
            m.add_expr(expr.into())
39✔
2447
        };
2448
        WriterExpr {
2449
            expr,
2450
            module: Rc::clone(&self.module),
13✔
2451
        }
2452
    }
2453

2454
    /// Create a new writer expression from a literal constant.
2455
    ///
2456
    /// # Example
2457
    ///
2458
    /// ```
2459
    /// # use bevy_hanabi::*;
2460
    /// let mut w = ExprWriter::new();
2461
    /// let x = w.lit(-3.5); // x = -3.5;
2462
    /// ```
2463
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2464
        self.push(Expr::Literal(LiteralExpr {
33✔
2465
            value: value.into(),
11✔
2466
        }))
2467
    }
2468

2469
    /// Create a new writer expression from an attribute.
2470
    ///
2471
    /// # Example
2472
    ///
2473
    /// ```
2474
    /// # use bevy_hanabi::*;
2475
    /// let mut w = ExprWriter::new();
2476
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2477
    /// ```
2478
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2479
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
3✔
2480
    }
2481

2482
    /// Create a new writer expression from an attribute on a parent effect.
2483
    ///
2484
    /// # Example
2485
    ///
2486
    /// ```
2487
    /// # use bevy_hanabi::*;
2488
    /// let mut w = ExprWriter::new();
2489
    /// let x = w.parent_attr(Attribute::POSITION); // x = parent_particle.position;
2490
    /// ```
2491
    pub fn parent_attr(&self, attr: Attribute) -> WriterExpr {
×
2492
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
2493
    }
2494

2495
    /// Create a new writer expression from a property.
2496
    ///
2497
    /// # Example
2498
    ///
2499
    /// ```
2500
    /// # use bevy_hanabi::*;
2501
    /// let mut w = ExprWriter::new();
2502
    /// let prop = w.add_property("my_prop", 3.0.into());
2503
    /// let x = w.prop(prop); // x = properties.my_prop;
2504
    /// ```
2505
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2506
        self.push(Expr::Property(PropertyExpr::new(handle)))
3✔
2507
    }
2508

2509
    /// Create a new writer expression representing the current simulation time.
2510
    ///
2511
    /// # Example
2512
    ///
2513
    /// ```
2514
    /// # use bevy_hanabi::*;
2515
    /// let mut w = ExprWriter::new();
2516
    /// let x = w.time(); // x = sim_params.time;
2517
    /// ```
2518
    pub fn time(&self) -> WriterExpr {
×
2519
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2520
    }
2521

2522
    /// Create a new writer expression representing the simulation delta time
2523
    /// since last frame.
2524
    ///
2525
    /// # Example
2526
    ///
2527
    /// ```
2528
    /// # use bevy_hanabi::*;
2529
    /// let mut w = ExprWriter::new();
2530
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2531
    /// ```
2532
    pub fn delta_time(&self) -> WriterExpr {
×
2533
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2534
    }
2535

2536
    /// Create a new writer expression representing a random value of the given
2537
    /// type.
2538
    ///
2539
    /// The type can be any scalar or vector type. Matrix types are not
2540
    /// supported. The random values generated are uniformly distributed in
2541
    /// `[0:1]`. For vectors, each component is sampled separately.
2542
    ///
2543
    /// # Panics
2544
    ///
2545
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2546
    ///
2547
    /// # Example
2548
    ///
2549
    /// ```
2550
    /// # use bevy_hanabi::*;
2551
    /// let mut w = ExprWriter::new();
2552
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2553
    /// ```
2554
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2555
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2556
            value_type.into(),
×
2557
        ))))
2558
    }
2559

2560
    /// Create a new writer expression representing the alpha cutoff value used
2561
    /// for alpha masking.
2562
    ///
2563
    /// This expression is only valid when used in the context of the fragment
2564
    /// shader, in the render context.
2565
    ///
2566
    /// # Example
2567
    ///
2568
    /// ```
2569
    /// # use bevy_hanabi::*;
2570
    /// let mut w = ExprWriter::new();
2571
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2572
    /// ```
2573
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2574
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2575
            BuiltInOperator::AlphaCutoff,
×
2576
        )))
2577
    }
2578

2579
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2580
    /// were written by the writer.
2581
    ///
2582
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2583
    /// to that effect the modifiers which use the expressions created by this
2584
    /// writer.
2585
    ///
2586
    /// # Example
2587
    ///
2588
    /// ```
2589
    /// # use bevy_hanabi::*;
2590
    /// # let spawner = SpawnerSettings::default();
2591
    /// let mut w = ExprWriter::new();
2592
    /// // [...]
2593
    /// let module = w.finish();
2594
    /// let asset = EffectAsset::new(256, spawner, module);
2595
    /// ```
2596
    ///
2597
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2598
    pub fn finish(self) -> Module {
3✔
2599
        self.module.take()
3✔
2600
    }
2601
}
2602

2603
/// Intermediate expression from an [`ExprWriter`].
2604
///
2605
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2606
/// retains a reference to the underlying [`Module`] and therefore can easily be
2607
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2608
/// being more heavyweight and locking the underlying [`Module`] under a
2609
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2610
/// opposition is a very lightweight type, similar to a simple index. And like
2611
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2612
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2613
///
2614
/// In addition, [`WriterExpr`] implements several numerical operators like the
2615
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2616
/// [`WriterExpr`].
2617
///
2618
/// ```
2619
/// # use bevy_hanabi::*;
2620
/// let mut w = ExprWriter::new();
2621
/// let x = w.lit(-3.5);
2622
/// let y = w.lit(78.);
2623
/// let z = x + y; // == 74.5
2624
/// ```
2625
///
2626
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2627
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2628
///
2629
/// ```
2630
/// # use bevy_hanabi::*;
2631
/// let mut w = ExprWriter::new();
2632
/// let my_prop = w.add_property("my_prop", 3.0.into());
2633
///
2634
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2635
/// let x = (w.lit(-3.5) + w.lit(1.))
2636
///     .max(w.prop(my_prop))
2637
///     .mul(w.lit(0.5))
2638
///     .sub(w.attr(Attribute::POSITION));
2639
///
2640
/// let handle: ExprHandle = x.expr();
2641
/// ```
2642
#[derive(Debug, Clone)]
2643
pub struct WriterExpr {
2644
    expr: ExprHandle,
2645
    module: Rc<RefCell<Module>>,
2646
}
2647

2648
impl WriterExpr {
2649
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2650
        let expr = self.module.borrow_mut().add_expr(Expr::Unary {
4✔
2651
            op,
1✔
2652
            expr: self.expr,
1✔
2653
        });
2654
        WriterExpr {
2655
            expr,
2656
            module: self.module,
1✔
2657
        }
2658
    }
2659

2660
    /// Take the absolute value of the current expression.
2661
    ///
2662
    /// This is a unary operator, which applies component-wise to vector and
2663
    /// matrix operand expressions.
2664
    ///
2665
    /// # Example
2666
    ///
2667
    /// ```
2668
    /// # use bevy_hanabi::*;
2669
    /// # let mut w = ExprWriter::new();
2670
    /// // A literal expression `x = -3.5;`.
2671
    /// let x = w.lit(-3.5);
2672
    ///
2673
    /// // The absolute value `y = abs(x);`.
2674
    /// let y = x.abs(); // == 3.5
2675
    /// ```
2676
    #[inline]
2677
    pub fn abs(self) -> Self {
1✔
2678
        self.unary_op(UnaryOperator::Abs)
3✔
2679
    }
2680

2681
    /// Apply the logical operator "all" to the current bool vector expression.
2682
    ///
2683
    /// This is a unary operator, which applies to vector operand expressions to
2684
    /// produce a scalar boolean.
2685
    ///
2686
    /// # Example
2687
    ///
2688
    /// ```
2689
    /// # use bevy_hanabi::*;
2690
    /// # use bevy::math::BVec3;
2691
    /// # let mut w = ExprWriter::new();
2692
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2693
    /// let x = w.lit(BVec3::new(true, false, true));
2694
    ///
2695
    /// // Check if all components are true `y = all(x);`.
2696
    /// let y = x.all(); // == false
2697
    /// ```
2698
    #[inline]
2699
    pub fn all(self) -> Self {
×
2700
        self.unary_op(UnaryOperator::All)
×
2701
    }
2702

2703
    /// Apply the logical operator "any" to the current bool vector expression.
2704
    ///
2705
    /// This is a unary operator, which applies to vector operand expressions to
2706
    /// produce a scalar boolean.
2707
    ///
2708
    /// # Example
2709
    ///
2710
    /// ```
2711
    /// # use bevy_hanabi::*;
2712
    /// # use bevy::math::BVec3;
2713
    /// # let mut w = ExprWriter::new();
2714
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2715
    /// let x = w.lit(BVec3::new(true, false, true));
2716
    ///
2717
    /// // Check if any components is true `y = any(x);`.
2718
    /// let y = x.any(); // == true
2719
    /// ```
2720
    #[inline]
2721
    pub fn any(self) -> Self {
×
2722
        self.unary_op(UnaryOperator::Any)
×
2723
    }
2724

2725
    /// Apply the "acos" (inverse cosine) operator to the current float scalar
2726
    /// or vector expression.
2727
    ///
2728
    /// This is a unary operator, which applies to float scalar or vector
2729
    /// operand expressions to produce a float scalar or vector. It applies
2730
    /// component-wise to vector operand expressions. The return value lies in
2731
    /// the 0 ≤ x ≤ π range.
2732
    ///
2733
    /// # Example
2734
    ///
2735
    /// ```
2736
    /// # use bevy_hanabi::*;
2737
    /// # use bevy::math::Vec3;
2738
    /// # let mut w = ExprWriter::new();
2739
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2740
    /// let x = w.lit(Vec3::ONE);
2741
    ///
2742
    /// // Acos: `y = acos(x);`
2743
    /// let y = x.acos();
2744
    /// ```
2745
    #[inline]
2746
    pub fn acos(self) -> Self {
×
2747
        self.unary_op(UnaryOperator::Acos)
×
2748
    }
2749

2750
    /// Apply the "asin" (inverse sine) operator to the current float scalar or
2751
    /// vector expression.
2752
    ///
2753
    /// This is a unary operator, which applies to float scalar or vector
2754
    /// operand expressions to produce a float scalar or vector. It applies
2755
    /// component-wise to vector operand expressions. The return value lies in
2756
    /// the -π/2 ≤ x ≤ π/2 range.
2757
    ///
2758
    /// # Example
2759
    ///
2760
    /// ```
2761
    /// # use bevy_hanabi::*;
2762
    /// # use bevy::math::Vec3;
2763
    /// # let mut w = ExprWriter::new();
2764
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2765
    /// let x = w.lit(Vec3::ONE);
2766
    ///
2767
    /// // Asin: `y = asin(x);`
2768
    /// let y = x.asin();
2769
    /// ```
2770
    #[inline]
2771
    pub fn asin(self) -> Self {
×
2772
        self.unary_op(UnaryOperator::Asin)
×
2773
    }
2774

2775
    /// Apply the "atan" (inverse tangent) operator to the current float scalar
2776
    /// or vector expression.
2777
    ///
2778
    /// This is a unary operator, which applies to float scalar or vector
2779
    /// operand expressions to produce a float scalar or vector. It applies
2780
    /// component-wise to vector operand expressions. The return value lies in
2781
    /// the -π/2 ≤ x ≤ π/2 range.
2782
    ///
2783
    /// # Example
2784
    ///
2785
    /// ```
2786
    /// # use bevy_hanabi::*;
2787
    /// # use bevy::math::Vec3;
2788
    /// # let mut w = ExprWriter::new();
2789
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2790
    /// let x = w.lit(Vec3::ONE);
2791
    ///
2792
    /// // Atan: `y = atan(x);`
2793
    /// let y = x.atan();
2794
    /// ```
2795
    #[inline]
2796
    pub fn atan(self) -> Self {
×
2797
        self.unary_op(UnaryOperator::Atan)
×
2798
    }
2799

2800
    /// Apply the "ceil" operator to the current float scalar or vector
2801
    /// expression.
2802
    ///
2803
    /// This is a unary operator, which applies to float scalar or vector
2804
    /// operand expressions to produce a float scalar or vector. It applies
2805
    /// component-wise to vector operand expressions.
2806
    ///
2807
    /// # Example
2808
    ///
2809
    /// ```
2810
    /// # use bevy_hanabi::*;
2811
    /// # use bevy::math::Vec3;
2812
    /// # let mut w = ExprWriter::new();
2813
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2814
    /// let x = w.lit(Vec3::ONE);
2815
    ///
2816
    /// // Ceil: `y = ceil(x);`
2817
    /// let y = x.ceil();
2818
    /// ```
2819
    #[inline]
2820
    pub fn ceil(self) -> Self {
×
2821
        self.unary_op(UnaryOperator::Ceil)
×
2822
    }
2823

2824
    /// Apply the "cos" operator to the current float scalar or vector
2825
    /// expression.
2826
    ///
2827
    /// This is a unary operator, which applies to float scalar or vector
2828
    /// operand expressions to produce a float scalar or vector. It applies
2829
    /// component-wise to vector operand expressions.
2830
    ///
2831
    /// # Example
2832
    ///
2833
    /// ```
2834
    /// # use bevy_hanabi::*;
2835
    /// # use bevy::math::Vec3;
2836
    /// # let mut w = ExprWriter::new();
2837
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2838
    /// let x = w.lit(Vec3::ONE);
2839
    ///
2840
    /// // Cos: `y = cos(x);`
2841
    /// let y = x.cos();
2842
    /// ```
2843
    #[inline]
2844
    pub fn cos(self) -> Self {
×
2845
        self.unary_op(UnaryOperator::Cos)
×
2846
    }
2847

2848
    /// Apply the "exp" operator to the current float scalar or vector
2849
    /// expression.
2850
    ///
2851
    /// This is a unary operator, which applies to float scalar or vector
2852
    /// operand expressions to produce a float scalar or vector. It applies
2853
    /// component-wise to vector operand expressions.
2854
    ///
2855
    /// # Example
2856
    ///
2857
    /// ```
2858
    /// # use bevy_hanabi::*;
2859
    /// # use bevy::math::Vec3;
2860
    /// # let mut w = ExprWriter::new();
2861
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2862
    /// let x = w.lit(Vec3::ONE);
2863
    ///
2864
    /// // Exp: `y = exp(x);`
2865
    /// let y = x.exp();
2866
    /// ```
2867
    #[inline]
2868
    pub fn exp(self) -> Self {
×
2869
        self.unary_op(UnaryOperator::Exp)
×
2870
    }
2871

2872
    /// Apply the "exp2" operator to the current float scalar or vector
2873
    /// expression.
2874
    ///
2875
    /// This is a unary operator, which applies to float scalar or vector
2876
    /// operand expressions to produce a float scalar or vector. It applies
2877
    /// component-wise to vector operand expressions.
2878
    ///
2879
    /// # Example
2880
    ///
2881
    /// ```
2882
    /// # use bevy_hanabi::*;
2883
    /// # use bevy::math::Vec3;
2884
    /// # let mut w = ExprWriter::new();
2885
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2886
    /// let x = w.lit(Vec3::ONE);
2887
    ///
2888
    /// // Exp2: `y = exp2(x);`
2889
    /// let y = x.exp2();
2890
    /// ```
2891
    #[inline]
2892
    pub fn exp2(self) -> Self {
×
2893
        self.unary_op(UnaryOperator::Exp2)
×
2894
    }
2895

2896
    /// Apply the "floor" operator to the current float scalar or vector
2897
    /// expression.
2898
    ///
2899
    /// This is a unary operator, which applies to float scalar or vector
2900
    /// operand expressions to produce a float scalar or vector. It applies
2901
    /// component-wise to vector operand expressions.
2902
    ///
2903
    /// # Example
2904
    ///
2905
    /// ```
2906
    /// # use bevy_hanabi::*;
2907
    /// # use bevy::math::Vec3;
2908
    /// # let mut w = ExprWriter::new();
2909
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2910
    /// let x = w.lit(Vec3::ONE);
2911
    ///
2912
    /// // Floor: `y = floor(x);`
2913
    /// let y = x.floor();
2914
    /// ```
2915
    #[inline]
2916
    pub fn floor(self) -> Self {
×
2917
        self.unary_op(UnaryOperator::Floor)
×
2918
    }
2919

2920
    /// Apply the "fract" operator to the current float scalar or vector
2921
    /// expression.
2922
    ///
2923
    /// This is a unary operator, which applies to float scalar or vector
2924
    /// operand expressions to produce a float scalar or vector. It applies
2925
    /// component-wise to vector operand expressions.
2926
    ///
2927
    /// # Example
2928
    ///
2929
    /// ```
2930
    /// # use bevy_hanabi::*;
2931
    /// # use bevy::math::Vec3;
2932
    /// # let mut w = ExprWriter::new();
2933
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2934
    /// let x = w.lit(Vec3::ONE);
2935
    ///
2936
    /// // Fract: `y = fract(x);`
2937
    /// let y = x.fract();
2938
    /// ```
2939
    #[inline]
2940
    pub fn fract(self) -> Self {
×
2941
        self.unary_op(UnaryOperator::Fract)
×
2942
    }
2943

2944
    /// Apply the "inverseSqrt" (inverse square root) operator to the current
2945
    /// float scalar or vector expression.
2946
    ///
2947
    /// This is a unary operator, which applies to float scalar or vector
2948
    /// operand expressions to produce a float scalar or vector. It applies
2949
    /// component-wise to vector operand expressions.
2950
    ///
2951
    /// # Example
2952
    ///
2953
    /// ```
2954
    /// # use bevy_hanabi::*;
2955
    /// # use bevy::math::Vec3;
2956
    /// # let mut w = ExprWriter::new();
2957
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2958
    /// let x = w.lit(Vec3::ONE);
2959
    ///
2960
    /// // Inverse square root: `y = inverseSqrt(x) = 1.0 / sqrt(x);`
2961
    /// let y = x.inverse_sqrt();
2962
    /// ```
2963
    #[inline]
2964
    pub fn inverse_sqrt(self) -> Self {
×
2965
        self.unary_op(UnaryOperator::InvSqrt)
×
2966
    }
2967

2968
    /// Apply the "length" operator to the current float scalar or vector
2969
    /// expression.
2970
    ///
2971
    /// This is a unary operator, which applies to float scalar or vector
2972
    /// operand expressions to produce a float scalar or vector. It applies
2973
    /// component-wise to vector operand expressions.
2974
    ///
2975
    /// # Example
2976
    ///
2977
    /// ```
2978
    /// # use bevy_hanabi::*;
2979
    /// # use bevy::math::Vec3;
2980
    /// # let mut w = ExprWriter::new();
2981
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2982
    /// let x = w.lit(Vec3::ONE);
2983
    ///
2984
    /// // Length: `y = length(x);`
2985
    /// let y = x.length();
2986
    /// ```
2987
    #[inline]
2988
    pub fn length(self) -> Self {
×
2989
        self.unary_op(UnaryOperator::Length)
×
2990
    }
2991

2992
    /// Apply the "log" operator to the current float scalar or vector
2993
    /// expression.
2994
    ///
2995
    /// This is a unary operator, which applies to float scalar or vector
2996
    /// operand expressions to produce a float scalar or vector. It applies
2997
    /// component-wise to vector operand expressions.
2998
    ///
2999
    /// # Example
3000
    ///
3001
    /// ```
3002
    /// # use bevy_hanabi::*;
3003
    /// # use bevy::math::Vec3;
3004
    /// # let mut w = ExprWriter::new();
3005
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3006
    /// let x = w.lit(Vec3::ONE);
3007
    ///
3008
    /// // Log: `y = log(x);`
3009
    /// let y = x.log();
3010
    /// ```
3011
    #[inline]
3012
    pub fn log(self) -> Self {
×
3013
        self.unary_op(UnaryOperator::Log)
×
3014
    }
3015

3016
    /// Apply the "log2" operator to the current float scalar or vector
3017
    /// expression.
3018
    ///
3019
    /// This is a unary operator, which applies to float scalar or vector
3020
    /// operand expressions to produce a float scalar or vector. It applies
3021
    /// component-wise to vector operand expressions.
3022
    ///
3023
    /// # Example
3024
    ///
3025
    /// ```
3026
    /// # use bevy_hanabi::*;
3027
    /// # use bevy::math::Vec3;
3028
    /// # let mut w = ExprWriter::new();
3029
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3030
    /// let x = w.lit(Vec3::ONE);
3031
    ///
3032
    /// // Log2: `y = log2(x);`
3033
    /// let y = x.log2();
3034
    /// ```
3035
    #[inline]
3036
    pub fn log2(self) -> Self {
×
3037
        self.unary_op(UnaryOperator::Log2)
×
3038
    }
3039

3040
    /// Apply the "normalize" operator to the current float vector expression.
3041
    ///
3042
    /// This is a unary operator, which applies to float vector operand
3043
    /// expressions to produce another float vector with unit length
3044
    /// (normalized).
3045
    ///
3046
    /// # Example
3047
    ///
3048
    /// ```
3049
    /// # use bevy_hanabi::*;
3050
    /// # use bevy::math::Vec3;
3051
    /// # let mut w = ExprWriter::new();
3052
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3053
    /// let x = w.lit(Vec3::ONE);
3054
    ///
3055
    /// // Normalize: `y = normalize(x);`
3056
    /// let y = x.normalized();
3057
    /// ```
3058
    #[inline]
3059
    pub fn normalized(self) -> Self {
×
3060
        self.unary_op(UnaryOperator::Normalize)
×
3061
    }
3062

3063
    /// Apply the "pack4x8snorm" operator to the current 4-component float
3064
    /// vector expression.
3065
    ///
3066
    /// This is a unary operator, which applies to 4-component float vector
3067
    /// operand expressions to produce a single `u32` scalar expression.
3068
    ///
3069
    /// # Example
3070
    ///
3071
    /// ```
3072
    /// # use bevy_hanabi::*;
3073
    /// # use bevy::math::Vec4;
3074
    /// # let mut w = ExprWriter::new();
3075
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
3076
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
3077
    ///
3078
    /// // Pack: `y = pack4x8snorm(x);`
3079
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
3080
    /// ```
3081
    #[inline]
3082
    pub fn pack4x8snorm(self) -> Self {
×
3083
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
3084
    }
3085

3086
    /// Apply the "pack4x8unorm" operator to the current 4-component float
3087
    /// vector expression.
3088
    ///
3089
    /// This is a unary operator, which applies to 4-component float vector
3090
    /// operand expressions to produce a single `u32` scalar expression.
3091
    ///
3092
    /// # Example
3093
    ///
3094
    /// ```
3095
    /// # use bevy_hanabi::*;
3096
    /// # use bevy::math::Vec4;
3097
    /// # let mut w = ExprWriter::new();
3098
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
3099
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
3100
    ///
3101
    /// // Pack: `y = pack4x8unorm(x);`
3102
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
3103
    /// ```
3104
    #[inline]
3105
    pub fn pack4x8unorm(self) -> Self {
×
3106
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
3107
    }
3108

3109
    /// Apply the "round" operator to the current float scalar or vector
3110
    /// expression.
3111
    ///
3112
    /// This is a unary operator, which applies to float scalar or vector
3113
    /// operand expressions to produce a float scalar or vector. It applies
3114
    /// component-wise to vector operand expressions.
3115
    ///
3116
    /// # Example
3117
    ///
3118
    /// ```
3119
    /// # use bevy_hanabi::*;
3120
    /// # use bevy::math::Vec3;
3121
    /// # let mut w = ExprWriter::new();
3122
    /// // A literal expression `x = vec3<f32>(1.5, -3.2, 0.75);`.
3123
    /// let x = w.lit(Vec3::new(1.5, -3.2, 0.75));
3124
    ///
3125
    /// // Sign: `y = round(x);`
3126
    /// let y = x.round();
3127
    /// ```
3128
    #[inline]
3129
    pub fn round(self) -> Self {
×
3130
        self.unary_op(UnaryOperator::Round)
×
3131
    }
3132

3133
    /// Apply the "sign" operator to the current float scalar or vector
3134
    /// expression.
3135
    ///
3136
    /// This is a unary operator, which applies to float scalar or vector
3137
    /// operand expressions to produce a float scalar or vector. It applies
3138
    /// component-wise to vector operand expressions.
3139
    ///
3140
    /// # Example
3141
    ///
3142
    /// ```
3143
    /// # use bevy_hanabi::*;
3144
    /// # use bevy::math::Vec3;
3145
    /// # let mut w = ExprWriter::new();
3146
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3147
    /// let x = w.lit(Vec3::ONE);
3148
    ///
3149
    /// // Sign: `y = sign(x);`
3150
    /// let y = x.sign();
3151
    /// ```
3152
    #[inline]
3153
    pub fn sign(self) -> Self {
×
3154
        self.unary_op(UnaryOperator::Sign)
×
3155
    }
3156

3157
    /// Apply the "sin" operator to the current float scalar or vector
3158
    /// expression.
3159
    ///
3160
    /// This is a unary operator, which applies to float scalar or vector
3161
    /// operand expressions to produce a float scalar or vector. It applies
3162
    /// component-wise to vector operand expressions.
3163
    ///
3164
    /// # Example
3165
    ///
3166
    /// ```
3167
    /// # use bevy_hanabi::*;
3168
    /// # use bevy::math::Vec3;
3169
    /// # let mut w = ExprWriter::new();
3170
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3171
    /// let x = w.lit(Vec3::ONE);
3172
    ///
3173
    /// // Sin: `y = sin(x);`
3174
    /// let y = x.sin();
3175
    /// ```
3176
    #[inline]
3177
    pub fn sin(self) -> Self {
×
3178
        self.unary_op(UnaryOperator::Sin)
×
3179
    }
3180

3181
    /// Apply the "sqrt" (square root) operator to the current float scalar or
3182
    /// vector expression.
3183
    ///
3184
    /// This is a unary operator, which applies to float scalar or vector
3185
    /// operand expressions to produce a float scalar or vector. It applies
3186
    /// component-wise to vector operand expressions.
3187
    ///
3188
    /// # Example
3189
    ///
3190
    /// ```
3191
    /// # use bevy_hanabi::*;
3192
    /// # use bevy::math::Vec3;
3193
    /// # let mut w = ExprWriter::new();
3194
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3195
    /// let x = w.lit(Vec3::ONE);
3196
    ///
3197
    /// // Square root: `y = sqrt(x);`
3198
    /// let y = x.sqrt();
3199
    /// ```
3200
    #[inline]
3201
    pub fn sqrt(self) -> Self {
×
3202
        self.unary_op(UnaryOperator::Sqrt)
×
3203
    }
3204

3205
    /// Apply the "tan" operator to the current float scalar or vector
3206
    /// expression.
3207
    ///
3208
    /// This is a unary operator, which applies to float scalar or vector
3209
    /// operand expressions to produce a float scalar or vector. It applies
3210
    /// component-wise to vector operand expressions.
3211
    ///
3212
    /// # Example
3213
    ///
3214
    /// ```
3215
    /// # use bevy_hanabi::*;
3216
    /// # use bevy::math::Vec3;
3217
    /// # let mut w = ExprWriter::new();
3218
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3219
    /// let x = w.lit(Vec3::ONE);
3220
    ///
3221
    /// // Tan: `y = tan(x);`
3222
    /// let y = x.tan();
3223
    /// ```
3224
    #[inline]
3225
    pub fn tan(self) -> Self {
×
3226
        self.unary_op(UnaryOperator::Tan)
×
3227
    }
3228

3229
    /// Apply the "unpack4x8snorm" operator to the current `u32` scalar
3230
    /// expression.
3231
    ///
3232
    /// This is a unary operator, which applies to `u32` scalar operand
3233
    /// expressions to produce a 4-component floating point vector of signed
3234
    /// normalized components in `[-1:1]`.
3235
    ///
3236
    /// # Example
3237
    ///
3238
    /// ```
3239
    /// # use bevy_hanabi::*;
3240
    /// # use bevy::math::Vec3;
3241
    /// # let mut w = ExprWriter::new();
3242
    /// // A literal expression `y = 0x7F007FFFu32;`.
3243
    /// let y = w.lit(0x7F007FFFu32);
3244
    ///
3245
    /// // Unpack: `x = unpack4x8snorm(y);`
3246
    /// let x = y.unpack4x8snorm(); // vec4<f32>(-1., 1., 0., 7.2)
3247
    /// ```
3248
    #[inline]
3249
    pub fn unpack4x8snorm(self) -> Self {
×
3250
        self.unary_op(UnaryOperator::Unpack4x8snorm)
×
3251
    }
3252

3253
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
3254
    /// expression.
3255
    ///
3256
    /// This is a unary operator, which applies to `u32` scalar operand
3257
    /// expressions to produce a 4-component floating point vector of unsigned
3258
    /// normalized components in `[0:1]`.
3259
    ///
3260
    /// # Example
3261
    ///
3262
    /// ```
3263
    /// # use bevy_hanabi::*;
3264
    /// # use bevy::math::Vec3;
3265
    /// # let mut w = ExprWriter::new();
3266
    /// // A literal expression `y = 0xFF00FF00u32;`.
3267
    /// let y = w.lit(0xFF00FF00u32);
3268
    ///
3269
    /// // Unpack: `x = unpack4x8unorm(y);`
3270
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
3271
    /// ```
3272
    #[inline]
3273
    pub fn unpack4x8unorm(self) -> Self {
×
3274
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
3275
    }
3276

3277
    /// Apply the "saturate" operator to the current float scalar or vector
3278
    /// expression.
3279
    ///
3280
    /// This is a unary operator, which applies to float scalar or vector
3281
    /// operand expressions to produce a float scalar or vector. It applies
3282
    /// component-wise to vector operand expressions.
3283
    ///
3284
    /// # Example
3285
    ///
3286
    /// ```
3287
    /// # use bevy_hanabi::*;
3288
    /// # use bevy::math::Vec3;
3289
    /// # let mut w = ExprWriter::new();
3290
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
3291
    /// let x = w.lit(Vec3::ONE);
3292
    ///
3293
    /// // Saturate: `y = saturate(x);`
3294
    /// let y = x.saturate();
3295
    /// ```
3296
    #[inline]
3297
    pub fn saturate(self) -> Self {
×
3298
        self.unary_op(UnaryOperator::Saturate)
×
3299
    }
3300

3301
    /// Get the first component of a scalar or vector.
3302
    ///
3303
    /// # Example
3304
    ///
3305
    /// ```
3306
    /// # use bevy_hanabi::*;
3307
    /// # use bevy::math::Vec3;
3308
    /// # let mut w = ExprWriter::new();
3309
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3310
    /// let v = w.lit(Vec3::ONE);
3311
    ///
3312
    /// // f = v.x;`
3313
    /// let f = v.x();
3314
    /// ```
3315
    #[inline]
3316
    pub fn x(self) -> Self {
×
3317
        self.unary_op(UnaryOperator::X)
×
3318
    }
3319

3320
    /// Get the second component of a vector.
3321
    ///
3322
    /// # Example
3323
    ///
3324
    /// ```
3325
    /// # use bevy_hanabi::*;
3326
    /// # use bevy::math::Vec3;
3327
    /// # let mut w = ExprWriter::new();
3328
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3329
    /// let v = w.lit(Vec3::ONE);
3330
    ///
3331
    /// // f = v.y;`
3332
    /// let f = v.y();
3333
    /// ```
3334
    #[inline]
3335
    pub fn y(self) -> Self {
×
3336
        self.unary_op(UnaryOperator::Y)
×
3337
    }
3338

3339
    /// Get the third component of a vector.
3340
    ///
3341
    /// # Example
3342
    ///
3343
    /// ```
3344
    /// # use bevy_hanabi::*;
3345
    /// # use bevy::math::Vec3;
3346
    /// # let mut w = ExprWriter::new();
3347
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3348
    /// let v = w.lit(Vec3::ONE);
3349
    ///
3350
    /// // f = v.z;`
3351
    /// let f = v.z();
3352
    /// ```
3353
    #[inline]
3354
    pub fn z(self) -> Self {
×
3355
        self.unary_op(UnaryOperator::Z)
×
3356
    }
3357

3358
    /// Get the fourth component of a vector.
3359
    ///
3360
    /// # Example
3361
    ///
3362
    /// ```
3363
    /// # use bevy_hanabi::*;
3364
    /// # use bevy::math::Vec3;
3365
    /// # let mut w = ExprWriter::new();
3366
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3367
    /// let v = w.lit(Vec3::ONE);
3368
    ///
3369
    /// // f = v.w;`
3370
    /// let f = v.w();
3371
    /// ```
3372
    #[inline]
3373
    pub fn w(self) -> Self {
×
3374
        self.unary_op(UnaryOperator::W)
×
3375
    }
3376

3377
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
3378
        assert_eq!(self.module, other.module);
5✔
3379
        let left = self.expr;
10✔
3380
        let right = other.expr;
10✔
3381
        let expr = self
15✔
3382
            .module
10✔
3383
            .borrow_mut()
3384
            .add_expr(Expr::Binary { op, left, right });
15✔
3385
        WriterExpr {
3386
            expr,
3387
            module: self.module,
5✔
3388
        }
3389
    }
3390

3391
    /// Add the current expression with another expression.
3392
    ///
3393
    /// This is a binary operator, which applies component-wise to vector
3394
    /// operand expressions.
3395
    ///
3396
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3397
    /// symbol, as an alternative to calling this method directly.
3398
    ///
3399
    /// # Example
3400
    ///
3401
    /// ```
3402
    /// # use bevy_hanabi::*;
3403
    /// # use bevy::math::Vec2;
3404
    /// # let mut w = ExprWriter::new();
3405
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3406
    /// let x = w.lit(Vec2::new(3., -2.));
3407
    ///
3408
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3409
    /// let y = w.lit(Vec2::new(1., 5.));
3410
    ///
3411
    /// // The sum of both vectors `z = x + y;`.
3412
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3413
    ///                   // -OR-
3414
    ///                   // let z = x + y;
3415
    /// ```
3416
    #[allow(clippy::should_implement_trait)]
3417
    #[inline]
3418
    pub fn add(self, other: Self) -> Self {
2✔
3419
        self.binary_op(other, BinaryOperator::Add)
8✔
3420
    }
3421

3422
    /// Apply the "atan2" (inverse tangent with 2 arguments) operator to the
3423
    /// current float scalar or vector expression.
3424
    ///
3425
    /// This is a unary operator, which applies to float scalar or vector
3426
    /// operand expressions to produce a float scalar or vector. It applies
3427
    /// component-wise to vector operand expressions. The return value lies in
3428
    /// the -π ≤ x ≤ π range, and represents a value whose tangent is equal to
3429
    /// y over x (`z = atan2(y, x)` <=> `tan(z) = y / x`).
3430
    ///
3431
    /// # Example
3432
    ///
3433
    /// ```
3434
    /// # use bevy_hanabi::*;
3435
    /// # use bevy::math::Vec3;
3436
    /// # let mut w = ExprWriter::new();
3437
    /// // Two literal expressions `x` and `y`.
3438
    /// let x = w.lit(Vec3::new(1., 0., -1.));
3439
    /// let y = w.lit(Vec3::ONE);
3440
    ///
3441
    /// // Atan: `z = atan2(y, x);`
3442
    /// let z = y.atan2(x);
3443
    /// ```
3444
    #[inline]
3445
    pub fn atan2(self, other: Self) -> Self {
×
3446
        self.binary_op(other, BinaryOperator::Atan2)
×
3447
    }
3448

3449
    /// Calculate the cross product of the current expression by another
3450
    /// expression.
3451
    ///
3452
    /// This is a binary operator, which applies to vector operands of size 3
3453
    /// only, and always produces a vector of the same size.
3454
    ///
3455
    /// # Example
3456
    ///
3457
    /// ```
3458
    /// # use bevy_hanabi::*;
3459
    /// # use bevy::math::Vec3;
3460
    /// # let mut w = ExprWriter::new();
3461
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3462
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3463
    ///
3464
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3465
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3466
    ///
3467
    /// // The cross product of both vectors `z = cross(x, y);`.
3468
    /// let z = x.cross(y);
3469
    /// ```
3470
    #[inline]
3471
    pub fn cross(self, other: Self) -> Self {
×
3472
        self.binary_op(other, BinaryOperator::Cross)
×
3473
    }
3474

3475
    /// Calculate the dot product of the current expression by another
3476
    /// expression.
3477
    ///
3478
    /// This is a binary operator, which applies to vector operands of same size
3479
    /// only, and always produces a floating point scalar.
3480
    ///
3481
    /// # Example
3482
    ///
3483
    /// ```
3484
    /// # use bevy_hanabi::*;
3485
    /// # use bevy::math::Vec2;
3486
    /// # let mut w = ExprWriter::new();
3487
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3488
    /// let x = w.lit(Vec2::new(3., -2.));
3489
    ///
3490
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3491
    /// let y = w.lit(Vec2::new(1., 5.));
3492
    ///
3493
    /// // The dot product of both vectors `z = dot(x, y);`.
3494
    /// let z = x.dot(y);
3495
    /// ```
3496
    #[inline]
3497
    pub fn dot(self, other: Self) -> Self {
×
3498
        self.binary_op(other, BinaryOperator::Dot)
×
3499
    }
3500

3501
    /// Calculate the distance between the current expression and another
3502
    /// expression.
3503
    ///
3504
    /// This is a binary operator.
3505
    ///
3506
    /// # Example
3507
    ///
3508
    /// ```
3509
    /// # use bevy_hanabi::*;
3510
    /// # use bevy::math::Vec3;
3511
    /// # let mut w = ExprWriter::new();
3512
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3513
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3514
    ///
3515
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3516
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3517
    ///
3518
    /// // The distance between the vectors `z = distance(x, y);`.
3519
    /// let z = x.distance(y);
3520
    /// ```
3521
    #[inline]
3522
    pub fn distance(self, other: Self) -> Self {
×
3523
        self.binary_op(other, BinaryOperator::Distance)
×
3524
    }
3525

3526
    /// Divide the current expression by another expression.
3527
    ///
3528
    /// This is a binary operator, which applies component-wise to vector
3529
    /// operand expressions.
3530
    ///
3531
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3532
    /// symbol, as an alternative to calling this method directly.
3533
    ///
3534
    /// # Example
3535
    ///
3536
    /// ```
3537
    /// # use bevy_hanabi::*;
3538
    /// # use bevy::math::Vec2;
3539
    /// # let mut w = ExprWriter::new();
3540
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3541
    /// let x = w.lit(Vec2::new(3., -2.));
3542
    ///
3543
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3544
    /// let y = w.lit(Vec2::new(1., 5.));
3545
    ///
3546
    /// // The quotient of both vectors `z = x / y;`.
3547
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3548
    ///                   // -OR-
3549
    ///                   // let z = x / y;
3550
    /// ```
3551
    #[allow(clippy::should_implement_trait)]
3552
    #[inline]
3553
    pub fn div(self, other: Self) -> Self {
×
3554
        self.binary_op(other, BinaryOperator::Div)
×
3555
    }
3556

3557
    /// Apply the logical operator "greater than or equal" to this expression
3558
    /// and another expression.
3559
    ///
3560
    /// This is a binary operator, which applies component-wise to vector
3561
    /// operand expressions.
3562
    ///
3563
    /// # Example
3564
    ///
3565
    /// ```
3566
    /// # use bevy_hanabi::*;
3567
    /// # use bevy::math::Vec3;
3568
    /// # let mut w = ExprWriter::new();
3569
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3570
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3571
    ///
3572
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3573
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3574
    ///
3575
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3576
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3577
    /// ```
3578
    #[inline]
3579
    pub fn ge(self, other: Self) -> Self {
×
3580
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3581
    }
3582

3583
    /// Apply the logical operator "greater than" to this expression and another
3584
    /// expression.
3585
    ///
3586
    /// This is a binary operator, which applies component-wise to vector
3587
    /// operand expressions.
3588
    ///
3589
    /// # Example
3590
    ///
3591
    /// ```
3592
    /// # use bevy_hanabi::*;
3593
    /// # use bevy::math::Vec3;
3594
    /// # let mut w = ExprWriter::new();
3595
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3596
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3597
    ///
3598
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3599
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3600
    ///
3601
    /// // The boolean result of the greater than operation `z = (x > y);`.
3602
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3603
    /// ```
3604
    #[inline]
3605
    pub fn gt(self, other: Self) -> Self {
×
3606
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3607
    }
3608

3609
    /// Apply the logical operator "less than or equal" to this expression and
3610
    /// another expression.
3611
    ///
3612
    /// This is a binary operator, which applies component-wise to vector
3613
    /// operand expressions.
3614
    ///
3615
    /// # Example
3616
    ///
3617
    /// ```
3618
    /// # use bevy_hanabi::*;
3619
    /// # use bevy::math::Vec3;
3620
    /// # let mut w = ExprWriter::new();
3621
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3622
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3623
    ///
3624
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3625
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3626
    ///
3627
    /// // The boolean result of the less than or equal operation `z = (x <= y);`.
3628
    /// let z = x.le(y); // == vec3<bool>(false, true, true)
3629
    /// ```
3630
    #[inline]
3631
    pub fn le(self, other: Self) -> Self {
×
3632
        self.binary_op(other, BinaryOperator::LessThanOrEqual)
×
3633
    }
3634

3635
    /// Apply the logical operator "less than" to this expression and another
3636
    /// expression.
3637
    ///
3638
    /// This is a binary operator, which applies component-wise to vector
3639
    /// operand expressions.
3640
    ///
3641
    /// # Example
3642
    ///
3643
    /// ```
3644
    /// # use bevy_hanabi::*;
3645
    /// # use bevy::math::Vec3;
3646
    /// # let mut w = ExprWriter::new();
3647
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3648
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3649
    ///
3650
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3651
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3652
    ///
3653
    /// // The boolean result of the less than operation `z = (x < y);`.
3654
    /// let z = x.lt(y); // == vec3<bool>(false, true, false)
3655
    /// ```
3656
    #[inline]
3657
    pub fn lt(self, other: Self) -> Self {
×
3658
        self.binary_op(other, BinaryOperator::LessThan)
×
3659
    }
3660

3661
    /// Take the maximum value of the current expression and another expression.
3662
    ///
3663
    /// This is a binary operator, which applies component-wise to vector
3664
    /// operand expressions.
3665
    ///
3666
    /// # Example
3667
    ///
3668
    /// ```
3669
    /// # use bevy_hanabi::*;
3670
    /// # use bevy::math::Vec2;
3671
    /// # let mut w = ExprWriter::new();
3672
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3673
    /// let x = w.lit(Vec2::new(3., -2.));
3674
    ///
3675
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3676
    /// let y = w.lit(Vec2::new(1., 5.));
3677
    ///
3678
    /// // The maximum of both vectors `z = max(x, y);`.
3679
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3680
    /// ```
3681
    #[inline]
3682
    pub fn max(self, other: Self) -> Self {
1✔
3683
        self.binary_op(other, BinaryOperator::Max)
4✔
3684
    }
3685

3686
    /// Take the minimum value of the current expression and another expression.
3687
    ///
3688
    /// This is a binary operator, which applies component-wise to vector
3689
    /// operand expressions.
3690
    ///
3691
    /// # Example
3692
    ///
3693
    /// ```
3694
    /// # use bevy_hanabi::*;
3695
    /// # use bevy::math::Vec2;
3696
    /// # let mut w = ExprWriter::new();
3697
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3698
    /// let x = w.lit(Vec2::new(3., -2.));
3699
    ///
3700
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3701
    /// let y = w.lit(Vec2::new(1., 5.));
3702
    ///
3703
    /// // The minimum of both vectors `z = min(x, y);`.
3704
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3705
    /// ```
3706
    #[inline]
3707
    pub fn min(self, other: Self) -> Self {
1✔
3708
        self.binary_op(other, BinaryOperator::Min)
4✔
3709
    }
3710

3711
    /// Multiply the current expression with another expression.
3712
    ///
3713
    /// This is a binary operator, which applies component-wise to vector
3714
    /// operand expressions.
3715
    ///
3716
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3717
    /// symbol, as an alternative to calling this method directly.
3718
    ///
3719
    /// # Example
3720
    ///
3721
    /// ```
3722
    /// # use bevy_hanabi::*;
3723
    /// # use bevy::math::Vec2;
3724
    /// # let mut w = ExprWriter::new();
3725
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3726
    /// let x = w.lit(Vec2::new(3., -2.));
3727
    ///
3728
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3729
    /// let y = w.lit(Vec2::new(1., 5.));
3730
    ///
3731
    /// // The product of both vectors `z = x * y;`.
3732
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3733
    ///                   // -OR-
3734
    ///                   // let z = x * y;
3735
    /// ```
3736
    #[allow(clippy::should_implement_trait)]
3737
    #[inline]
3738
    pub fn mul(self, other: Self) -> Self {
1✔
3739
        self.binary_op(other, BinaryOperator::Mul)
4✔
3740
    }
3741

3742
    /// Apply the logical operator "normal" to this expression and another
3743
    /// expression.
3744
    ///
3745
    /// This is a binary operator, which applies component-wise to vector
3746
    /// operand expressions. That is, for vectors, this produces a vector of
3747
    /// random values where each component is normally distributed with a mean
3748
    /// of the corresponding component of the first operand and a standard
3749
    /// deviation of the corresponding component of the second operand.
3750
    ///
3751
    /// # Example
3752
    ///
3753
    /// ```
3754
    /// # use bevy_hanabi::*;
3755
    /// # use bevy::math::Vec3;
3756
    /// # let mut w = ExprWriter::new();
3757
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3758
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3759
    ///
3760
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3761
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3762
    ///
3763
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3764
    /// let z = x.normal(y);
3765
    /// ```
3766
    #[inline]
3767
    pub fn normal(self, other: Self) -> Self {
×
3768
        self.binary_op(other, BinaryOperator::NormalRand)
×
3769
    }
3770

3771
    /// Calculate the remainder of the division of the current expression by
3772
    /// another expression.
3773
    ///
3774
    /// This is a binary operator.
3775
    ///
3776
    /// # Example
3777
    ///
3778
    /// ```
3779
    /// # use bevy_hanabi::*;
3780
    /// # use bevy::math::Vec3;
3781
    /// # let mut w = ExprWriter::new();
3782
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3783
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3784
    ///
3785
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3786
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3787
    ///
3788
    /// // The remainder of the division `z = x % y;`.
3789
    /// let z = x.rem(y);
3790
    /// ```
3791
    #[allow(clippy::should_implement_trait)]
3792
    #[inline]
3793
    pub fn rem(self, other: Self) -> Self {
×
3794
        self.binary_op(other, BinaryOperator::Remainder)
×
3795
    }
3796

3797
    /// Calculate the step of a value with respect to a reference.
3798
    ///
3799
    /// This is a binary operator, which applies component-wise to vector
3800
    /// operand expressions.
3801
    ///
3802
    /// # Example
3803
    ///
3804
    /// ```
3805
    /// # use bevy_hanabi::*;
3806
    /// # use bevy::math::Vec3;
3807
    /// # let mut w = ExprWriter::new();
3808
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3809
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3810
    ///
3811
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3812
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3813
    ///
3814
    /// // The step value
3815
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3816
    /// ```
3817
    #[allow(clippy::should_implement_trait)]
3818
    #[inline]
3819
    pub fn step(self, edge: Self) -> Self {
×
3820
        // Note: order is step(edge, x) but x.step(edge)
3821
        edge.binary_op(self, BinaryOperator::Step)
×
3822
    }
3823

3824
    /// Subtract another expression from the current expression.
3825
    ///
3826
    /// This is a binary operator, which applies component-wise to vector
3827
    /// operand expressions.
3828
    ///
3829
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3830
    /// symbol, as an alternative to calling this method directly.
3831
    ///
3832
    /// # Example
3833
    ///
3834
    /// ```
3835
    /// # use bevy_hanabi::*;
3836
    /// # use bevy::math::Vec2;
3837
    /// # let mut w = ExprWriter::new();
3838
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3839
    /// let x = w.lit(Vec2::new(3., -2.));
3840
    ///
3841
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3842
    /// let y = w.lit(Vec2::new(1., 5.));
3843
    ///
3844
    /// // The difference of both vectors `z = x - y;`.
3845
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3846
    ///                   // -OR-
3847
    ///                   // let z = x - y;
3848
    /// ```
3849
    #[allow(clippy::should_implement_trait)]
3850
    #[inline]
3851
    pub fn sub(self, other: Self) -> Self {
×
3852
        self.binary_op(other, BinaryOperator::Sub)
×
3853
    }
3854

3855
    /// Apply the logical operator "uniform" to this expression and another
3856
    /// expression.
3857
    ///
3858
    /// This is a binary operator, which applies component-wise to vector
3859
    /// operand expressions. That is, for vectors, this produces a vector of
3860
    /// random values where each component is uniformly distributed within the
3861
    /// bounds of the related component of both operands.
3862
    ///
3863
    /// # Example
3864
    ///
3865
    /// ```
3866
    /// # use bevy_hanabi::*;
3867
    /// # use bevy::math::Vec3;
3868
    /// # let mut w = ExprWriter::new();
3869
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3870
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3871
    ///
3872
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3873
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3874
    ///
3875
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3876
    /// let z = x.uniform(y);
3877
    /// ```
3878
    #[inline]
3879
    pub fn uniform(self, other: Self) -> Self {
×
3880
        self.binary_op(other, BinaryOperator::UniformRand)
×
3881
    }
3882

3883
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3884
        assert_eq!(self.module, second.module);
×
3885
        assert_eq!(self.module, third.module);
×
3886
        let first = self.expr;
×
3887
        let second = second.expr;
×
3888
        let third = third.expr;
×
3889
        let expr = self.module.borrow_mut().add_expr(Expr::Ternary {
×
3890
            op,
×
3891
            first,
×
3892
            second,
×
3893
            third,
×
3894
        });
3895
        WriterExpr {
3896
            expr,
3897
            module: self.module,
×
3898
        }
3899
    }
3900

3901
    /// Blending linearly ("mix") two expressions with the fraction provided by
3902
    /// a third expression.
3903
    ///
3904
    /// This is a ternary operator, which applies component-wise to vector
3905
    /// operand expressions.
3906
    ///
3907
    /// # Example
3908
    ///
3909
    /// ```
3910
    /// # use bevy_hanabi::*;
3911
    /// # use bevy::math::Vec2;
3912
    /// # let mut w = ExprWriter::new();
3913
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3914
    /// let x = w.lit(Vec2::new(3., -2.));
3915
    ///
3916
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3917
    /// let y = w.lit(Vec2::new(1., 4.));
3918
    ///
3919
    /// // A fraction `t = 0.5;`.
3920
    /// let t = w.lit(0.25);
3921
    ///
3922
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3923
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3924
    /// ```
3925
    #[inline]
3926
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3927
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3928
    }
3929

3930
    /// Clamp an expression between the bounds defined by two other expressions.
3931
    ///
3932
    /// This is a ternary operator, which applies component-wise to vector
3933
    /// operand expressions.
3934
    ///
3935
    /// # Example
3936
    ///
3937
    /// ```
3938
    /// # use bevy_hanabi::*;
3939
    /// # use bevy::math::Vec2;
3940
    /// # let mut w = ExprWriter::new();
3941
    /// // A literal expression `x = vec2<f32>(1., -2.);`.
3942
    /// let x = w.lit(Vec2::new(1., -2.));
3943
    ///
3944
    /// // A literal expression `lo = vec2<f32>(3., -3.);`.
3945
    /// let lo = w.lit(Vec2::new(3., -3.));
3946
    ///
3947
    /// // A literal expression `hi = vec2<f32>(5., 1.);`.
3948
    /// let hi = w.lit(Vec2::new(5., 1.));
3949
    ///
3950
    /// // Clamp x in [lo:hi]
3951
    /// let z = x.clamp(lo, hi); // == vec2<f32>(3., -2.)
3952
    /// ```
3953
    #[inline]
3954
    pub fn clamp(self, lo: Self, hi: Self) -> Self {
×
3955
        self.ternary_op(lo, hi, TernaryOperator::Clamp)
×
3956
    }
3957

3958
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3959
    /// value taken between the given bounds.
3960
    ///
3961
    /// This is a ternary operator, which applies component-wise to vector
3962
    /// operand expressions.
3963
    ///
3964
    /// # Example
3965
    ///
3966
    /// ```
3967
    /// # use bevy_hanabi::*;
3968
    /// # use bevy::math::Vec2;
3969
    /// # let mut w = ExprWriter::new();
3970
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3971
    /// let low = w.lit(Vec2::new(3., -2.));
3972
    ///
3973
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3974
    /// let high = w.lit(Vec2::new(1., 4.));
3975
    ///
3976
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3977
    /// let x = w.lit(Vec2::new(2., 1.));
3978
    ///
3979
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3980
    /// let t = x.smoothstep(low, high); // == 0.5
3981
    /// ```
3982
    #[inline]
3983
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3984
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3985
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3986
    }
3987

3988
    /// Construct a `Vec2` from two scalars.
3989
    ///
3990
    /// # Example
3991
    ///
3992
    /// ```
3993
    /// # use bevy_hanabi::*;
3994
    /// # let mut w = ExprWriter::new();
3995
    /// let theta = w.add_property("theta", 0.0.into());
3996
    /// // Convert the angular property `theta` to a 2D vector.
3997
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3998
    /// let circle_pos = cos_theta.vec2(sin_theta);
3999
    /// ```
4000
    #[inline]
4001
    pub fn vec2(self, y: Self) -> Self {
×
4002
        self.binary_op(y, BinaryOperator::Vec2)
×
4003
    }
4004

4005
    /// Construct a `Vec3` from two scalars.
4006
    ///
4007
    /// # Example
4008
    ///
4009
    /// ```
4010
    /// # use bevy_hanabi::*;
4011
    /// # let mut w = ExprWriter::new();
4012
    /// let theta = w.add_property("theta", 0.0.into());
4013
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
4014
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
4015
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
4016
    /// ```
4017
    #[inline]
4018
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
4019
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
4020
    }
4021

4022
    /// Construct a `Vec4` from a vector XYZ and a scalar W.
4023
    ///
4024
    /// # Example
4025
    ///
4026
    /// ```
4027
    /// # use bevy_hanabi::*;
4028
    /// # let mut w = ExprWriter::new();
4029
    /// let rgb = w.rand(VectorType::VEC3F);
4030
    /// let a = w.lit(1.);
4031
    /// // Build vec4<f32>(R, G, B, A) and convert to 0xAABBGGRR
4032
    /// let col = rgb.vec4_xyz_w(a).pack4x8unorm();
4033
    /// ```
4034
    #[inline]
4035
    pub fn vec4_xyz_w(self, w: Self) -> Self {
×
4036
        self.binary_op(w, BinaryOperator::Vec4XyzW)
×
4037
    }
4038

4039
    /// Cast an expression to a different type.
4040
    ///
4041
    /// # Example
4042
    ///
4043
    /// ```
4044
    /// # use bevy_hanabi::*;
4045
    /// # use bevy::math::Vec2;
4046
    /// # let mut w = ExprWriter::new();
4047
    /// let x = w.lit(Vec2::new(3., -2.));
4048
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
4049
    /// ```
4050
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
4051
        let target = target.into();
×
4052
        let expr = self
×
4053
            .module
×
4054
            .borrow_mut()
4055
            .add_expr(Expr::Cast(CastExpr::new(self.expr, target)));
×
4056
        WriterExpr {
4057
            expr,
4058
            module: self.module,
×
4059
        }
4060
    }
4061

4062
    /// Finalize an expression chain and return the accumulated expression.
4063
    ///
4064
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
4065
    /// this intermediate expression was built from.
4066
    ///
4067
    /// # Example
4068
    ///
4069
    /// ```
4070
    /// # use bevy_hanabi::*;
4071
    /// # let mut w = ExprWriter::new();
4072
    /// // A literal expression `x = -3.5;`.
4073
    /// let x = w.lit(-3.5);
4074
    ///
4075
    /// // Retrieve the ExprHandle for that expression.
4076
    /// let handle = x.expr();
4077
    /// ```
4078
    #[inline]
4079
    pub fn expr(self) -> ExprHandle {
8✔
4080
        self.expr
8✔
4081
    }
4082
}
4083

4084
impl std::ops::Add<WriterExpr> for WriterExpr {
4085
    type Output = WriterExpr;
4086

4087
    #[inline]
4088
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
4089
        self.add(rhs)
6✔
4090
    }
4091
}
4092

4093
impl std::ops::Sub<WriterExpr> for WriterExpr {
4094
    type Output = WriterExpr;
4095

4096
    #[inline]
4097
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
4098
        self.sub(rhs)
×
4099
    }
4100
}
4101

4102
impl std::ops::Mul<WriterExpr> for WriterExpr {
4103
    type Output = WriterExpr;
4104

4105
    #[inline]
4106
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
4107
        self.mul(rhs)
3✔
4108
    }
4109
}
4110

4111
impl std::ops::Div<WriterExpr> for WriterExpr {
4112
    type Output = WriterExpr;
4113

4114
    #[inline]
4115
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
4116
        self.div(rhs)
×
4117
    }
4118
}
4119

4120
impl std::ops::Rem<WriterExpr> for WriterExpr {
4121
    type Output = WriterExpr;
4122

4123
    #[inline]
4124
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
4125
        self.rem(rhs)
×
4126
    }
4127
}
4128

4129
#[cfg(test)]
4130
mod tests {
4131
    use bevy::{platform::collections::HashSet, prelude::*};
4132
    use ron::ser::PrettyConfig;
4133

4134
    use super::*;
4135
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
4136

4137
    #[test]
4138
    fn module() {
4139
        let mut m = Module::default();
4140

4141
        #[allow(unsafe_code)]
4142
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
4143
        assert!(m.get(unknown).is_none());
4144
        assert!(m.get_mut(unknown).is_none());
4145
        assert!(matches!(
4146
            m.try_get(unknown),
4147
            Err(ExprError::InvalidExprHandleError(_))
4148
        ));
4149
        assert!(matches!(
4150
            m.try_get_mut(unknown),
4151
            Err(ExprError::InvalidExprHandleError(_))
4152
        ));
4153

4154
        let x = m.lit(5.);
4155
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
4156
        assert_eq!(m.get(x), Some(&expected));
4157
        assert_eq!(m.get_mut(x), Some(&mut expected));
4158
        assert_eq!(m.try_get(x), Ok(&expected));
4159
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
4160
    }
4161

4162
    #[test]
4163
    fn local_var() {
4164
        let property_layout = PropertyLayout::default();
4165
        let particle_layout = ParticleLayout::default();
4166
        let mut ctx =
4167
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4168
        let mut h = HashSet::new();
4169
        for _ in 0..100 {
4170
            let v = ctx.make_local_var();
4171
            assert!(h.insert(v));
4172
        }
4173
    }
4174

4175
    #[test]
4176
    fn make_fn() {
4177
        let property_layout = PropertyLayout::default();
4178
        let particle_layout = ParticleLayout::default();
4179
        let mut ctx =
4180
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4181
        let mut module = Module::default();
4182

4183
        // Make a function
4184
        let func_name = "my_func";
4185
        let args = "arg0: i32, arg1: f32";
4186
        assert!(ctx
4187
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
4188
                m.lit(3.);
4189
                let v = ctx.make_local_var();
4190
                assert_eq!(v, "var0");
4191
                let code = String::new();
4192
                Ok(code)
4193
            })
4194
            .is_ok());
4195

4196
        // The local function context doesn't influence the outer caller context
4197
        let v = ctx.make_local_var();
4198
        assert_eq!(v, "var0");
4199

4200
        // However the module is common to the outer caller and the function
4201
        assert!(!module.expressions.is_empty());
4202
    }
4203

4204
    #[test]
4205
    fn property() {
4206
        let mut m = Module::default();
4207

4208
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
4209
        let _other_prop = m.add_property(
4210
            "other_prop",
4211
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
4212
        );
4213

4214
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
4215
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
4216
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
4217
    }
4218

4219
    #[test]
4220
    fn writer() {
4221
        // Get a module and its writer
4222
        let w = ExprWriter::new();
4223
        let my_prop = w.add_property("my_prop", 3.0.into());
4224

4225
        // Build some expression
4226
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
4227
            + w.lit(-4.).min(w.prop(my_prop));
4228
        let x = x.expr();
4229

4230
        // Create an evaluation context
4231
        let property_layout =
4232
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
4233
        let particle_layout = ParticleLayout::default();
4234
        let m = w.finish();
4235
        let mut context =
4236
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4237

4238
        // Evaluate the expression
4239
        let x = m.try_get(x).unwrap();
4240
        let s = x.eval(&m, &mut context).unwrap();
4241
        assert_eq!(
4242
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties[properties_offset].my_prop))"
4243
                .to_string(),
4244
            s
4245
        );
4246
    }
4247

4248
    #[test]
4249
    fn type_error() {
4250
        let l = Value::Scalar(3.5_f32.into());
4251
        let r: Result<Vec2, ExprError> = l.try_into();
4252
        assert!(r.is_err());
4253
        assert!(matches!(r, Err(ExprError::TypeError(_))));
4254
    }
4255

4256
    #[test]
4257
    fn math_expr() {
4258
        let mut m = Module::default();
4259

4260
        let x = m.attr(Attribute::POSITION);
4261
        let y = m.lit(Vec3::ONE);
4262

4263
        let add = m.add(x, y);
4264
        let sub = m.sub(x, y);
4265
        let mul = m.mul(x, y);
4266
        let div = m.div(x, y);
4267
        let rem = m.rem(x, y);
4268
        let lt = m.lt(x, y);
4269
        let le = m.le(x, y);
4270
        let gt = m.gt(x, y);
4271
        let ge = m.ge(x, y);
4272

4273
        let property_layout = PropertyLayout::default();
4274
        let particle_layout = ParticleLayout::default();
4275
        let mut ctx =
4276
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4277

4278
        for (expr, op) in [
4279
            (add, "+"),
4280
            (sub, "-"),
4281
            (mul, "*"),
4282
            (div, "/"),
4283
            (rem, "%"),
4284
            (lt, "<"),
4285
            (le, "<="),
4286
            (gt, ">"),
4287
            (ge, ">="),
4288
        ] {
4289
            let expr = ctx.eval(&m, expr);
4290
            assert!(expr.is_ok());
4291
            let expr = expr.unwrap();
4292
            assert_eq!(
4293
                expr,
4294
                format!(
4295
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
4296
                    Attribute::POSITION.name(),
4297
                    op,
4298
                )
4299
            );
4300
        }
4301
    }
4302

4303
    #[test]
4304
    fn builtin_expr() {
4305
        let mut m = Module::default();
4306

4307
        // Simulation parameters
4308
        let builtin_ops = [
4309
            BuiltInOperator::Time,
4310
            BuiltInOperator::DeltaTime,
4311
            BuiltInOperator::VirtualTime,
4312
            BuiltInOperator::VirtualDeltaTime,
4313
            BuiltInOperator::RealTime,
4314
            BuiltInOperator::RealDeltaTime,
4315
        ];
4316
        for op in builtin_ops {
4317
            let handle = m.builtin(op);
4318

4319
            {
4320
                let expr = m.get(handle);
4321
                assert!(expr.is_some());
4322
                let expr = expr.unwrap();
4323
                assert!(matches!(*expr, Expr::BuiltIn(_)));
4324
                if let Expr::BuiltIn(op) = expr {
4325
                    assert!(builtin_ops.contains(&op.operator));
4326
                }
4327
            }
4328

4329
            let property_layout = PropertyLayout::default();
4330
            let particle_layout = ParticleLayout::default();
4331
            let mut ctx =
4332
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4333

4334
            let expr = ctx.eval(&m, handle);
4335
            assert!(expr.is_ok());
4336
            let expr = expr.unwrap();
4337
            assert_eq!(expr, format!("sim_params.{}", op.name()));
4338
        }
4339

4340
        // Exercise the expression introspection
4341
        for (handle, expr) in m.expressions() {
4342
            assert!(handle.index() < m.expressions.len());
4343
            assert!(matches!(*expr, Expr::BuiltIn(_)));
4344
            if let Expr::BuiltIn(op) = expr {
4345
                assert!(builtin_ops.contains(&op.operator));
4346
            }
4347
        }
4348

4349
        // is_alive
4350
        {
4351
            let value = m.builtin(BuiltInOperator::IsAlive);
4352

4353
            let property_layout = PropertyLayout::default();
4354
            let particle_layout = ParticleLayout::default();
4355
            let mut ctx =
4356
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4357

4358
            let expr = ctx.eval(&m, value);
4359
            assert!(expr.is_ok());
4360
            let expr = expr.unwrap();
4361
            assert_eq!(expr, "is_alive");
4362
        }
4363

4364
        // BuiltInOperator::Rand (which has side effect)
4365
        for (scalar_type, prefix) in [
4366
            (ScalarType::Bool, "b"),
4367
            (ScalarType::Float, "f"),
4368
            (ScalarType::Int, "i"),
4369
            (ScalarType::Uint, "u"),
4370
        ] {
4371
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
4372

4373
            // Scalar form
4374
            {
4375
                let property_layout = PropertyLayout::default();
4376
                let particle_layout = ParticleLayout::default();
4377
                let mut ctx =
4378
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4379

4380
                let expr = ctx.eval(&m, value);
4381
                assert!(expr.is_ok());
4382
                let expr = expr.unwrap();
4383
                assert_eq!(expr, "var0");
4384
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
4385
            }
4386

4387
            // Vector form
4388
            for count in 2..=4 {
4389
                let vec = m.builtin(BuiltInOperator::Rand(
4390
                    VectorType::new(scalar_type, count).into(),
4391
                ));
4392

4393
                let property_layout = PropertyLayout::default();
4394
                let particle_layout = ParticleLayout::default();
4395
                let mut ctx =
4396
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4397

4398
                let expr = ctx.eval(&m, vec);
4399
                assert!(expr.is_ok());
4400
                let expr = expr.unwrap();
4401
                assert_eq!(expr, "var0");
4402
                assert_eq!(
4403
                    ctx.main_code,
4404
                    format!("let var0 = {}rand{}();\n", prefix, count)
4405
                );
4406
            }
4407
        }
4408
    }
4409

4410
    #[test]
4411
    fn unary_expr() {
4412
        let mut m = Module::default();
4413

4414
        let x = m.attr(Attribute::POSITION);
4415
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
4416
        let z = m.lit(BVec3::new(false, true, false));
4417
        let w = m.lit(Vec4::W);
4418
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
4419
        let us = m.lit(0x0u32);
4420
        let uu = m.lit(0x0u32);
4421

4422
        let abs = m.abs(x);
4423
        let acos = m.acos(w);
4424
        let all = m.all(z);
4425
        let any = m.any(z);
4426
        let asin = m.asin(w);
4427
        let atan = m.atan(w);
4428
        let ceil = m.ceil(y);
4429
        let cos = m.cos(y);
4430
        let exp = m.exp(y);
4431
        let exp2 = m.exp2(y);
4432
        let floor = m.floor(y);
4433
        let fract = m.fract(y);
4434
        let inv_sqrt = m.inverse_sqrt(y);
4435
        let length = m.length(y);
4436
        let log = m.log(y);
4437
        let log2 = m.log2(y);
4438
        let norm = m.normalize(y);
4439
        let pack4x8snorm = m.pack4x8snorm(v);
4440
        let pack4x8unorm = m.pack4x8unorm(v);
4441
        let round = m.round(y);
4442
        let saturate = m.saturate(y);
4443
        let sign = m.sign(y);
4444
        let sin = m.sin(y);
4445
        let sqrt = m.sqrt(y);
4446
        let tan = m.tan(y);
4447
        let unpack4x8snorm = m.unpack4x8snorm(us);
4448
        let unpack4x8unorm = m.unpack4x8unorm(uu);
4449
        let comp_x = m.x(w);
4450
        let comp_y = m.y(w);
4451
        let comp_z = m.z(w);
4452
        let comp_w = m.w(w);
4453

4454
        let property_layout = PropertyLayout::default();
4455
        let particle_layout = ParticleLayout::default();
4456
        let mut ctx =
4457
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4458

4459
        for (expr, op, inner) in [
4460
            (
4461
                abs,
4462
                "abs",
4463
                &format!("particle.{}", Attribute::POSITION.name())[..],
4464
            ),
4465
            (acos, "acos", "vec4<f32>(0.,0.,0.,1.)"),
4466
            (all, "all", "vec3<bool>(false,true,false)"),
4467
            (any, "any", "vec3<bool>(false,true,false)"),
4468
            (asin, "asin", "vec4<f32>(0.,0.,0.,1.)"),
4469
            (atan, "atan", "vec4<f32>(0.,0.,0.,1.)"),
4470
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
4471
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
4472
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
4473
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
4474
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
4475
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
4476
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
4477
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
4478
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
4479
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
4480
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
4481
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4482
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4483
            (round, "round", "vec3<f32>(1.,-3.1,6.99)"),
4484
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4485
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4486
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4487
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4488
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4489
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4490
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4491
        ] {
4492
            let expr = ctx.eval(&m, expr);
4493
            assert!(expr.is_ok());
4494
            let expr = expr.unwrap();
4495
            assert_eq!(expr, format!("{}({})", op, inner));
4496
        }
4497

4498
        for (expr, op, inner) in [
4499
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4500
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4501
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4502
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4503
        ] {
4504
            let expr = ctx.eval(&m, expr);
4505
            assert!(expr.is_ok());
4506
            let expr = expr.unwrap();
4507
            assert_eq!(expr, format!("{}.{}", inner, op));
4508
        }
4509
    }
4510

4511
    #[test]
4512
    fn binary_expr() {
4513
        let mut m = Module::default();
4514

4515
        let x = m.attr(Attribute::POSITION);
4516
        let y = m.lit(Vec3::ONE);
4517
        let z = m.lit(1.45);
4518

4519
        let atan2 = m.atan2(x, y);
4520
        let cross = m.cross(x, y);
4521
        let dist = m.distance(x, y);
4522
        let dot = m.dot(x, y);
4523
        let min = m.min(x, y);
4524
        let max = m.max(x, y);
4525
        let step = m.step(x, y);
4526
        let vec4_xyz_w = m.vec4_xyz_w(x, z);
4527

4528
        let property_layout = PropertyLayout::default();
4529
        let particle_layout = ParticleLayout::default();
4530
        let mut ctx =
4531
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4532

4533
        for (expr, op) in [
4534
            (atan2, "atan2"),
4535
            (cross, "cross"),
4536
            (dist, "distance"),
4537
            (dot, "dot"),
4538
            (min, "min"),
4539
            (max, "max"),
4540
            (step, "step"),
4541
        ] {
4542
            let expr = ctx.eval(&m, expr);
4543
            assert!(expr.is_ok());
4544
            let expr = expr.unwrap();
4545
            assert_eq!(
4546
                expr,
4547
                format!(
4548
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4549
                    op,
4550
                    Attribute::POSITION.name(),
4551
                )
4552
            );
4553
        }
4554

4555
        {
4556
            let expr = ctx.eval(&m, vec4_xyz_w);
4557
            assert!(expr.is_ok());
4558
            let expr = expr.unwrap();
4559
            let z = ctx.eval(&m, z).unwrap();
4560
            assert_eq!(
4561
                expr,
4562
                format!("vec4(particle.{}, {})", Attribute::POSITION.name(), z)
4563
            );
4564
        }
4565
    }
4566

4567
    #[test]
4568
    fn ternary_expr() {
4569
        let mut m = Module::default();
4570

4571
        let x = m.attr(Attribute::POSITION);
4572
        let y = m.lit(Vec3::ONE);
4573
        let z = m.lit(Vec3::splat(2.));
4574
        let t = m.lit(0.3);
4575
        let a = m.lit(-4.2);
4576
        let b = m.lit(53.09);
4577

4578
        let mix = m.mix(x, y, t);
4579
        let clamp = m.clamp(x, y, z);
4580
        let smoothstep = m.smoothstep(x, y, x);
4581
        let vecthree = m.vec3(a, b, t);
4582

4583
        let property_layout = PropertyLayout::default();
4584
        let particle_layout = ParticleLayout::default();
4585
        let mut ctx =
4586
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4587

4588
        for (expr, op, third) in [
4589
            (mix, "mix", t),
4590
            (clamp, "clamp", z),
4591
            (smoothstep, "smoothstep", x),
4592
        ] {
4593
            let expr = ctx.eval(&m, expr);
4594
            assert!(expr.is_ok());
4595
            let expr = expr.unwrap();
4596
            let third = ctx.eval(&m, third).unwrap();
4597
            assert_eq!(
4598
                expr,
4599
                format!(
4600
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4601
                    op,
4602
                    Attribute::POSITION.name(),
4603
                    third
4604
                )
4605
            );
4606
        }
4607

4608
        {
4609
            let expr = ctx.eval(&m, vecthree);
4610
            assert!(expr.is_ok());
4611
            let expr = expr.unwrap();
4612
            let a = ctx.eval(&m, a).unwrap();
4613
            let b = ctx.eval(&m, b).unwrap();
4614
            let t = ctx.eval(&m, t).unwrap();
4615
            assert_eq!(expr, format!("vec3({}, {}, {})", a, b, t));
4616
        }
4617
    }
4618

4619
    #[test]
4620
    fn cast_expr() {
4621
        let mut m = Module::default();
4622

4623
        let x = m.attr(Attribute::POSITION);
4624
        let y = m.lit(IVec2::ONE);
4625
        let z = m.lit(0.3);
4626
        let w = m.lit(false);
4627

4628
        let cx = m.cast(x, VectorType::VEC3I);
4629
        let cy = m.cast(y, VectorType::VEC2U);
4630
        let cz = m.cast(z, ScalarType::Int);
4631
        let cw = m.cast(w, ScalarType::Uint);
4632

4633
        let property_layout = PropertyLayout::default();
4634
        let particle_layout = ParticleLayout::default();
4635
        let mut ctx =
4636
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4637

4638
        for (expr, cast, target) in [
4639
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4640
            (y, cy, VectorType::VEC2U.into()),
4641
            (z, cz, ScalarType::Int.into()),
4642
            (w, cw, ScalarType::Uint.into()),
4643
        ] {
4644
            let expr = ctx.eval(&m, expr);
4645
            assert!(expr.is_ok());
4646
            let expr = expr.unwrap();
4647
            let cast = ctx.eval(&m, cast);
4648
            assert!(cast.is_ok());
4649
            let cast = cast.unwrap();
4650
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4651
        }
4652
    }
4653

4654
    #[test]
4655
    fn attribute_pointer() {
4656
        let mut m = Module::default();
4657
        let x = m.attr(Attribute::POSITION);
4658

4659
        let property_layout = PropertyLayout::default();
4660
        let particle_layout = ParticleLayout::default();
4661
        let mut ctx =
4662
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4663

4664
        let res = ctx.eval(&m, x);
4665
        assert!(res.is_ok());
4666
        let xx = res.ok().unwrap();
4667
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4668

4669
        // Use a different context; it's invalid to reuse a mutated context, as the
4670
        // expression cache will have been generated with the wrong context.
4671
        let mut ctx =
4672
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4673
                .with_attribute_pointer();
4674

4675
        let res = ctx.eval(&m, x);
4676
        assert!(res.is_ok());
4677
        let xx = res.ok().unwrap();
4678
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4679
    }
4680

4681
    #[test]
4682
    #[should_panic]
4683
    fn invalid_cast_vector_to_scalar() {
4684
        let mut m = Module::default();
4685
        let x = m.lit(Vec2::ONE);
4686
        let _ = m.cast(x, ScalarType::Float);
4687
    }
4688

4689
    #[test]
4690
    #[should_panic]
4691
    fn invalid_cast_matrix_to_scalar() {
4692
        let mut m = Module::default();
4693
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4694
        let _ = m.cast(x, ScalarType::Float);
4695
    }
4696

4697
    #[test]
4698
    #[should_panic]
4699
    fn invalid_cast_matrix_to_vector() {
4700
        let mut m = Module::default();
4701
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4702
        let _ = m.cast(x, VectorType::VEC4F);
4703
    }
4704

4705
    #[test]
4706
    #[should_panic]
4707
    fn invalid_cast_scalar_to_matrix() {
4708
        let mut m = Module::default();
4709
        let x = m.lit(3.);
4710
        let _ = m.cast(x, MatrixType::MAT3X3F);
4711
    }
4712

4713
    #[test]
4714
    #[should_panic]
4715
    fn invalid_cast_vector_to_matrix() {
4716
        let mut m = Module::default();
4717
        let x = m.lit(Vec3::ZERO);
4718
        let _ = m.cast(x, MatrixType::MAT2X4F);
4719
    }
4720

4721
    #[test]
4722
    fn cast_expr_new() {
4723
        let mut m = Module::default();
4724

4725
        let x = m.attr(Attribute::POSITION);
4726
        let c = CastExpr::new(x, VectorType::VEC3F);
4727
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4728
        assert_eq!(c.is_valid(&m), Some(true));
4729

4730
        let x = m.attr(Attribute::POSITION);
4731
        let c = CastExpr::new(x, ScalarType::Bool);
4732
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4733
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4734

4735
        let p = m.add_property("my_prop", 3.0.into());
4736
        let y = m.prop(p);
4737
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4738
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4739
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4740
    }
4741

4742
    #[test]
4743
    fn side_effect() {
4744
        let mut m = Module::default();
4745

4746
        // Adding the same cloned expression with side effect to itself should yield
4747
        // twice the value, and not two separate evaluations of the expression.
4748
        // CORRECT:
4749
        //   let r = frand();
4750
        //   r + r
4751
        // INCORRECT:
4752
        //   frand() + frand()
4753

4754
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4755
        let r2 = r;
4756
        let r3 = r2;
4757
        let a = m.add(r, r2);
4758
        let b = m.mix(r, r2, r3);
4759
        let c = m.abs(a);
4760

4761
        {
4762
            let property_layout = PropertyLayout::default();
4763
            let particle_layout = ParticleLayout::default();
4764
            let mut ctx =
4765
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4766
            let value = ctx.eval(&m, a).unwrap();
4767
            assert_eq!(value, "(var0) + (var0)");
4768
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4769
        }
4770

4771
        {
4772
            let property_layout = PropertyLayout::default();
4773
            let particle_layout = ParticleLayout::default();
4774
            let mut ctx =
4775
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4776
            let value = ctx.eval(&m, b).unwrap();
4777
            assert_eq!(value, "mix(var0, var0, var0)");
4778
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4779
        }
4780

4781
        {
4782
            let property_layout = PropertyLayout::default();
4783
            let particle_layout = ParticleLayout::default();
4784
            let mut ctx =
4785
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4786
            let value = ctx.eval(&m, c).unwrap();
4787
            assert_eq!(value, "abs((var0) + (var0))");
4788
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4789
        }
4790
    }
4791

4792
    // #[test]
4793
    // fn serde() {
4794
    //     let v = Value::Scalar(3.0_f32.into());
4795
    //     let l: LiteralExpr = v.into();
4796
    //     assert_eq!(Ok(v), l.eval());
4797
    //     let s = ron::to_string(&l).unwrap();
4798
    //     println!("literal: {:?}", s);
4799
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4800
    //     assert_eq!(l_serde, l);
4801

4802
    //     let b: ExprHandle = Box::new(l);
4803
    //     let s = ron::to_string(&b).unwrap();
4804
    //     println!("boxed literal: {:?}", s);
4805
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4806
    //     assert!(b_serde.is_const());
4807
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4808

4809
    //     let v0 = Value::Scalar(3.0_f32.into());
4810
    //     let v1 = Value::Scalar(2.5_f32.into());
4811
    //     let l0: LiteralExpr = v0.into();
4812
    //     let l1: LiteralExpr = v1.into();
4813
    //     let a = l0 + l1;
4814
    //     assert!(a.is_const());
4815
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4816
    //     let s = ron::to_string(&a).unwrap();
4817
    //     println!("add: {:?}", s);
4818
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4819
    //     println!("a_serde: {:?}", a_serde);
4820
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4821
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4822
    // }
4823

4824
    #[test]
4825
    fn expr_handle_serde() {
4826
        let handle = ExprHandle {
4827
            id: NonZeroU32::new(42).unwrap(),
4828
        };
4829

4830
        // ser
4831
        let s = ron::ser::to_string_pretty(&handle, PrettyConfig::default()).unwrap();
4832
        eprintln!("{}", s);
4833

4834
        // de
4835
        {
4836
            let mut de = ron::de::Deserializer::from_str(&s).unwrap();
4837
            let serde_handle = ExprHandle::deserialize(&mut de).unwrap();
4838
            assert_eq!(handle, serde_handle);
4839
        }
4840

4841
        // de -- literatl string
4842
        {
4843
            let mut de = ron::de::Deserializer::from_str("\"#42\"").unwrap();
4844
            let serde_handle = ExprHandle::deserialize(&mut de).unwrap();
4845
            assert_eq!(handle, serde_handle);
4846
        }
4847

4848
        // de -- invalid string
4849
        {
4850
            let mut de = ron::de::Deserializer::from_str("\"invalid\"").unwrap();
4851
            let ret = ExprHandle::deserialize(&mut de);
4852
            assert!(ret.is_err());
4853
        }
4854

4855
        // de -- literal (not supported)
4856
        {
4857
            let mut de = ron::de::Deserializer::from_str("33").unwrap();
4858
            let ret = ExprHandle::deserialize(&mut de);
4859
            assert!(ret.is_err());
4860
        }
4861

4862
        // de -- invalid ID (zero)
4863
        {
4864
            let mut de = ron::de::Deserializer::from_str("\"#0\"").unwrap();
4865
            let ret = ExprHandle::deserialize(&mut de);
4866
            assert!(ret.is_err());
4867
        }
4868

4869
        // de -- invalid ID (negative)
4870
        {
4871
            let mut de = ron::de::Deserializer::from_str("\"#-5\"").unwrap();
4872
            let ret = ExprHandle::deserialize(&mut de);
4873
            assert!(ret.is_err());
4874
        }
4875

4876
        // de -- valid ID (u32::MAX)
4877
        {
4878
            let mut de = ron::de::Deserializer::from_str("\"#4294967295\"").unwrap();
4879
            let serde_handle = ExprHandle::deserialize(&mut de).unwrap();
4880
            assert_eq!(serde_handle.id.get(), u32::MAX);
4881
        }
4882

4883
        // de -- invalid ID (u32::MAX + 1; out of bounds)
4884
        {
4885
            let mut de = ron::de::Deserializer::from_str("\"#4294967296\"").unwrap();
4886
            let ret = ExprHandle::deserialize(&mut de);
4887
            assert!(ret.is_err());
4888
        }
4889
    }
4890
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc