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

djeedai / bevy_hanabi / 13886117903

16 Mar 2025 06:17PM UTC coverage: 40.141% (-0.003%) from 40.144%
13886117903

Pull #437

github

web-flow
Merge 960bc0841 into 7e122b2be
Pull Request #437: Color changes to allow random firework colors

21 of 41 new or added lines in 4 files covered. (51.22%)

121 existing lines in 1 file now uncovered.

3245 of 8084 relevant lines covered (40.14%)

18.6 hits per line

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

52.24
/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::{prelude::default, reflect::Reflect};
108
use serde::{Deserialize, Serialize};
109
use thiserror::Error;
110

111
use super::Value;
112
use crate::{
113
    Attribute, ModifierContext, ParticleLayout, Property, PropertyLayout, ScalarType,
114
    TextureLayout, TextureSlot, ToWgslString, ValueType, VectorType,
115
};
116

117
/// A one-based ID into a collection of a [`Module`].
118
type Id = NonZeroU32;
119

120
/// Handle of an expression inside a given [`Module`].
121
///
122
/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a
123
/// lightweight representation, similar to a simple array index. For this
124
/// reason, it's easily copyable. However it's also lacking any kind of error
125
/// checking, and mixing handles to different modules produces undefined
126
/// behaviors (like an index does when indexing the wrong array).
127
#[derive(
128
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
129
)]
130
#[repr(transparent)]
131
#[serde(transparent)]
132
pub struct ExprHandle {
133
    id: Id,
134
}
135

136
impl ExprHandle {
137
    /// Create a new handle from a 1-based [`Id`].
138
    #[allow(dead_code)]
139
    fn new(id: Id) -> Self {
×
140
        Self { id }
141
    }
142

143
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
144
    /// the index is known to be non-zero already.
145
    #[allow(unsafe_code)]
146
    unsafe fn new_unchecked(id: usize) -> Self {
233✔
147
        debug_assert!(id != 0);
466✔
148
        Self {
149
            id: NonZeroU32::new_unchecked(id as u32),
233✔
150
        }
151
    }
152

153
    /// Get the zero-based index into the array of the module.
154
    fn index(&self) -> usize {
395✔
155
        (self.id.get() - 1) as usize
395✔
156
    }
157
}
158

159
/// Handle of a property inside a given [`Module`].
160
///
161
/// A handle uniquely references a [`Property`] stored inside a [`Module`]. It's
162
/// a lightweight representation, similar to a simple array index. For this
163
/// reason, it's easily copyable. However it's also lacking any kind of error
164
/// checking, and mixing handles to different modules produces undefined
165
/// behaviors (like an index does when indexing the wrong array).
166
#[derive(
167
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
168
)]
169
#[repr(transparent)]
170
#[serde(transparent)]
171
pub struct PropertyHandle {
172
    id: Id,
173
}
174

175
impl PropertyHandle {
176
    /// Create a new handle from a 1-based [`Id`].
177
    #[allow(dead_code)]
178
    fn new(id: Id) -> Self {
×
179
        Self { id }
180
    }
181

182
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
183
    /// the index is known to be non-zero already.
184
    #[allow(unsafe_code)]
185
    unsafe fn new_unchecked(id: usize) -> Self {
6✔
186
        debug_assert!(id != 0);
12✔
187
        Self {
188
            id: NonZeroU32::new_unchecked(id as u32),
6✔
189
        }
190
    }
191

192
    /// Get the zero-based index into the array of the module.
193
    fn index(&self) -> usize {
2✔
194
        (self.id.get() - 1) as usize
2✔
195
    }
196
}
197

198
/// Handle of a texture inside a given [`Module`].
199
///
200
/// A handle uniquely references a [`TextureSlot`] stored inside a [`Module`].
201
/// It's a lightweight representation, similar to a simple array index. For this
202
/// reason, it's easily copyable. However it's also lacking any kind of error
203
/// checking, and mixing handles to different modules produces undefined
204
/// behaviors (like an index does when indexing the wrong array).
205
#[derive(
206
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
207
)]
208
#[repr(transparent)]
209
#[serde(transparent)]
210
pub struct TextureHandle {
211
    id: Id,
212
}
213

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

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

231
    /// Get the zero-based index into the array of the module.
232
    #[allow(dead_code)]
233
    fn index(&self) -> usize {
×
234
        (self.id.get() - 1) as usize
×
235
    }
236
}
237

238
/// Container for expressions.
239
///
240
/// A module represents a storage for a set of expressions used in a single
241
/// [`EffectAsset`]. Modules are not reusable accross effect assets; each effect
242
/// asset owns a single module, containing all the expressions used in all the
243
/// modifiers attached to that asset. However, for convenience, a module can be
244
/// cloned into an unrelated module, and the clone can be assigned to another
245
/// effect asset.
246
///
247
/// Modules are built incrementally. Expressions are written into the module
248
/// through convenience helpers like [`lit()`] or [`attr()`]. Alternatively, an
249
/// [`ExprWriter`] can be used to populate a new or existing module. Either way,
250
/// once an expression is written into a module, it cannot be modified or
251
/// deleted. Modules are not designed to be used as editing structures, but as
252
/// storage and serialization ones.
253
///
254
/// [`EffectAsset`]: crate::EffectAsset
255
/// [`lit()`]: Module::lit
256
/// [`attr()`]: Module::attr
257
#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)]
258
pub struct Module {
259
    /// Expressions defined in the module.
260
    expressions: Vec<Expr>,
261
    /// Properties used as part of a [`PropertyExpr`].
262
    properties: Vec<Property>,
263
    /// Texture layout.
264
    texture_layout: TextureLayout,
265
}
266

267
macro_rules! impl_module_unary {
268
    ($t: ident, $T: ident) => {
269
        #[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).")]
270
        #[inline]
271
        pub fn $t(&mut self, inner: ExprHandle) -> ExprHandle {
38✔
272
            self.unary(UnaryOperator::$T, inner)
38✔
273
        }
274
    };
275
}
276

277
macro_rules! impl_module_binary {
278
    ($t: ident, $T: ident) => {
279
        #[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).")]
280
        #[inline]
281
        pub fn $t(&mut self, left: ExprHandle, right: ExprHandle) -> ExprHandle {
34✔
282
            self.binary(BinaryOperator::$T, left, right)
34✔
283
        }
284
    };
285
}
286

287
macro_rules! impl_module_ternary {
288
    ($t: ident, $T: ident) => {
289
        #[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).")]
290
        #[inline]
291
        pub fn $t(&mut self, first: ExprHandle, second: ExprHandle, third: ExprHandle) -> ExprHandle {
3✔
292
            self.ternary(TernaryOperator::$T, first, second, third)
3✔
293
        }
294
    };
295
}
296

297
impl Module {
298
    /// Create a new module from an existing collection of expressions.
299
    pub fn from_raw(expr: Vec<Expr>) -> Self {
×
300
        Self {
301
            expressions: expr,
302
            properties: vec![],
×
303
            texture_layout: default(),
×
304
        }
305
    }
306

307
    /// Add a new property to the module.
308
    ///
309
    /// See [`Property`] for more details on what effect properties are.
310
    ///
311
    /// # Panics
312
    ///
313
    /// Panics if a property with the same name already exists.
314
    pub fn add_property(
6✔
315
        &mut self,
316
        name: impl Into<String>,
317
        default_value: Value,
318
    ) -> PropertyHandle {
319
        let name = name.into();
6✔
320
        assert!(!self.properties.iter().any(|p| p.name() == name));
13✔
321
        self.properties.push(Property::new(name, default_value));
6✔
322
        // SAFETY - We just pushed a new property into the array, so its length is
323
        // non-zero.
324
        #[allow(unsafe_code)]
6✔
325
        unsafe {
326
            PropertyHandle::new_unchecked(self.properties.len())
6✔
327
        }
328
    }
329

330
    /// Get an existing property by handle.
331
    ///
332
    /// Existing properties are properties previously created with
333
    /// [`add_property()`].
334
    ///
335
    /// [`add_property()`]: crate::Module::add_property
336
    pub fn get_property(&self, property: PropertyHandle) -> Option<&Property> {
2✔
337
        self.properties.get(property.index())
2✔
338
    }
339

340
    /// Get an existing property by name.
341
    ///
342
    /// Existing properties are properties previously created with
343
    /// [`add_property()`].
344
    ///
345
    /// [`add_property()`]: crate::Module::add_property
346
    pub fn get_property_by_name(&self, name: &str) -> Option<PropertyHandle> {
×
347
        self.properties
×
348
            .iter()
349
            .enumerate()
350
            .find(|(_, prop)| prop.name() == name)
×
351
            .map(|(index, _)| PropertyHandle::new(NonZeroU32::new(index as u32 + 1).unwrap()))
×
352
    }
353

354
    /// Get the list of existing properties.
355
    pub fn properties(&self) -> &[Property] {
9✔
356
        &self.properties
9✔
357
    }
358

359
    /// Add a new texture slot to the module.
360
    ///
361
    /// The `name` parameter defines a new [`TextureSlot`] associated with this
362
    /// module, and must be unique inside this module. A unique index is also
363
    /// associated with the slot, corresponding to the value returned by
364
    /// [`TextureLayout::get_slot_by_name()`].
365
    ///
366
    /// Once a slot is added, an actual texture resource, defined by its
367
    /// `Handle<Image>`, is bound to that slot through the
368
    /// [`EffectMaterial`] component. Expressions like [`TextureSampleExpr`] can
369
    /// be used to sample the texture using the returned [`TextureHandle`].
370
    ///
371
    /// # Returns
372
    ///
373
    /// The handle of the texture inside this module. This handle is used in
374
    /// expressions like the [`TextureSampleExpr`] to reference this texture
375
    /// slot.
376
    ///
377
    /// # Panics
378
    ///
379
    /// Panics if a texture slot with the same name already exists inside this
380
    /// module. Different effect asset (different modules) can have the same
381
    /// slot name.
382
    ///
383
    /// [`EffectMaterial`]: crate::EffectMaterial
384
    pub fn add_texture_slot(&mut self, name: impl Into<String>) -> TextureHandle {
×
385
        let name = name.into();
×
386
        assert!(!self.texture_layout.layout.iter().any(|t| t.name == name));
×
387
        self.texture_layout.layout.push(TextureSlot { name });
×
388
        // SAFETY - We just pushed a new slot into the array, so its length is non-zero.
389
        #[allow(unsafe_code)]
×
390
        unsafe {
391
            TextureHandle::new_unchecked(self.texture_layout.layout.len())
×
392
        }
393
    }
394

395
    /// Append a new expression to the module.
396
    fn push(&mut self, expr: impl Into<Expr>) -> ExprHandle {
232✔
397
        self.expressions.push(expr.into());
232✔
398
        #[allow(unsafe_code)]
232✔
399
        unsafe {
400
            ExprHandle::new_unchecked(self.expressions.len())
232✔
401
        }
402
    }
403

404
    /// Build a literal expression and append it to the module.
405
    #[inline]
406
    pub fn lit<V>(&mut self, value: V) -> ExprHandle
75✔
407
    where
408
        Value: From<V>,
409
    {
410
        self.push(Expr::Literal(LiteralExpr::new(value)))
75✔
411
    }
412

413
    /// Build an attribute expression and append it to the module.
414
    #[inline]
415
    pub fn attr(&mut self, attr: Attribute) -> ExprHandle {
26✔
416
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
26✔
417
    }
418

419
    /// Build a parent attribute expression and append it to the module.
420
    #[inline]
421
    pub fn parent_attr(&mut self, attr: Attribute) -> ExprHandle {
×
422
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
423
    }
424

425
    /// Build a property expression and append it to the module.
426
    ///
427
    /// A property expression retrieves the value of the given property.
428
    #[inline]
429
    pub fn prop(&mut self, property: PropertyHandle) -> ExprHandle {
3✔
430
        self.push(Expr::Property(PropertyExpr::new(property)))
3✔
431
    }
432

433
    /// Build a built-in expression and append it to the module.
434
    #[inline]
435
    pub fn builtin(&mut self, op: BuiltInOperator) -> ExprHandle {
30✔
436
        self.push(Expr::BuiltIn(BuiltInExpr::new(op)))
30✔
437
    }
438

439
    /// Build a unary expression and append it to the module.
440
    ///
441
    /// The handle to the expression representing the operand of the unary
442
    /// operation must be valid, that is reference an expression
443
    /// contained in the current [`Module`].
444
    ///
445
    /// # Panics
446
    ///
447
    /// Panics in some cases if the operand handle do not reference an existing
448
    /// expression in the current module. Note however that this check can
449
    /// miss some invalid handles (false negative), so only represents an
450
    /// extra safety net that users shouldn't rely exclusively on
451
    /// to ensure the operand handles are valid. Instead, it's the
452
    /// responsibility of the user to ensure the operand handle references an
453
    /// existing expression in the current [`Module`].
454
    #[inline]
455
    pub fn unary(&mut self, op: UnaryOperator, inner: ExprHandle) -> ExprHandle {
38✔
456
        assert!(inner.index() < self.expressions.len());
38✔
457
        self.push(Expr::Unary { op, expr: inner })
38✔
458
    }
459

460
    impl_module_unary!(abs, Abs);
461
    impl_module_unary!(acos, Acos);
462
    impl_module_unary!(asin, Asin);
463
    impl_module_unary!(atan, Atan);
464
    impl_module_unary!(all, All);
465
    impl_module_unary!(any, Any);
466
    impl_module_unary!(ceil, Ceil);
467
    impl_module_unary!(cos, Cos);
468
    impl_module_unary!(exp, Exp);
469
    impl_module_unary!(exp2, Exp2);
470
    impl_module_unary!(floor, Floor);
471
    impl_module_unary!(fract, Fract);
472
    impl_module_unary!(inverse_sqrt, InvSqrt);
473
    impl_module_unary!(length, Length);
474
    impl_module_unary!(log, Log);
475
    impl_module_unary!(log2, Log2);
476
    impl_module_unary!(normalize, Normalize);
477
    impl_module_unary!(pack4x8snorm, Pack4x8snorm);
478
    impl_module_unary!(pack4x8unorm, Pack4x8unorm);
479
    impl_module_unary!(round, Round);
480
    impl_module_unary!(saturate, Saturate);
481
    impl_module_unary!(sign, Sign);
482
    impl_module_unary!(sin, Sin);
483
    impl_module_unary!(sqrt, Sqrt);
484
    impl_module_unary!(tan, Tan);
485
    impl_module_unary!(unpack4x8snorm, Unpack4x8snorm);
486
    impl_module_unary!(unpack4x8unorm, Unpack4x8unorm);
487
    impl_module_unary!(w, W);
488
    impl_module_unary!(x, X);
489
    impl_module_unary!(y, Y);
490
    impl_module_unary!(z, Z);
491

492
    /// Build a binary expression and append it to the module.
493
    ///
494
    /// The handles to the expressions representing the left and right operands
495
    /// of the binary operation must be valid, that is reference expressions
496
    /// contained in the current [`Module`].
497
    ///
498
    /// # Panics
499
    ///
500
    /// Panics in some cases if either of the left or right operand handles do
501
    /// not reference existing expressions in the current module. Note however
502
    /// that this check can miss some invalid handles (false negative), so only
503
    /// represents an extra safety net that users shouldn't rely exclusively on
504
    /// to ensure the operand handles are valid. Instead, it's the
505
    /// responsibility of the user to ensure handles reference existing
506
    /// expressions in the current [`Module`].
507
    #[inline]
508
    pub fn binary(
34✔
509
        &mut self,
510
        op: BinaryOperator,
511
        left: ExprHandle,
512
        right: ExprHandle,
513
    ) -> ExprHandle {
514
        assert!(left.index() < self.expressions.len());
34✔
515
        assert!(right.index() < self.expressions.len());
34✔
516
        self.push(Expr::Binary { op, left, right })
34✔
517
    }
518

519
    impl_module_binary!(add, Add);
520
    impl_module_binary!(atan2, Atan2);
521
    impl_module_binary!(cross, Cross);
522
    impl_module_binary!(distance, Distance);
523
    impl_module_binary!(div, Div);
524
    impl_module_binary!(dot, Dot);
525
    impl_module_binary!(ge, GreaterThanOrEqual);
526
    impl_module_binary!(gt, GreaterThan);
527
    impl_module_binary!(le, LessThanOrEqual);
528
    impl_module_binary!(lt, LessThan);
529
    impl_module_binary!(max, Max);
530
    impl_module_binary!(min, Min);
531
    impl_module_binary!(mul, Mul);
532
    impl_module_binary!(rem, Remainder);
533
    impl_module_binary!(step, Step);
534
    impl_module_binary!(sub, Sub);
535
    impl_module_binary!(uniform, UniformRand);
536
    impl_module_binary!(normal, NormalRand);
537
    impl_module_binary!(vec2, Vec2);
538

539
    /// Build a ternary expression and append it to the module.
540
    ///
541
    /// The handles to the expressions representing the three operands of the
542
    /// ternary operation must be valid, that is reference expressions
543
    /// contained in the current [`Module`].
544
    ///
545
    /// # Panics
546
    ///
547
    /// Panics in some cases if any of the operand handles do not reference
548
    /// existing expressions in the current module. Note however
549
    /// that this check can miss some invalid handles (false negative), so only
550
    /// represents an extra safety net that users shouldn't rely exclusively on
551
    /// to ensure the operand handles are valid. Instead, it's the
552
    /// responsibility of the user to ensure handles reference existing
553
    /// expressions in the current [`Module`].
554
    #[inline]
555
    pub fn ternary(
3✔
556
        &mut self,
557
        op: TernaryOperator,
558
        first: ExprHandle,
559
        second: ExprHandle,
560
        third: ExprHandle,
561
    ) -> ExprHandle {
562
        assert!(first.index() < self.expressions.len());
3✔
563
        assert!(second.index() < self.expressions.len());
3✔
564
        assert!(third.index() < self.expressions.len());
3✔
565
        self.push(Expr::Ternary {
3✔
566
            op,
3✔
567
            first,
3✔
568
            second,
3✔
569
            third,
3✔
570
        })
571
    }
572

573
    impl_module_ternary!(mix, Mix);
574
    impl_module_ternary!(smoothstep, SmoothStep);
575

576
    /// Build a cast expression and append it to the module.
577
    ///
578
    /// The handle to the expressions representing the operand of the cast
579
    /// operation must be valid, that is reference expressions contained in
580
    /// the current [`Module`].
581
    ///
582
    /// # Panics
583
    ///
584
    /// Panics in some cases if the operand handle does not reference existing
585
    /// expressions in the current module. Note however that this check can
586
    /// miss some invalid handles (false negative), so only represents an
587
    /// extra safety net that users shouldn't rely exclusively on
588
    /// to ensure the operand handles are valid. Instead, it's the
589
    /// responsibility of the user to ensure handles reference existing
590
    /// expressions in the current [`Module`].
591
    ///
592
    /// Panics if the resulting cast expression is not valid. See
593
    /// [`CastExpr::is_valid()`] for the exact meaning.
594
    pub fn cast(&mut self, expr: ExprHandle, target: impl Into<ValueType>) -> ExprHandle {
9✔
595
        assert!(expr.index() < self.expressions.len());
9✔
596
        let target = target.into();
9✔
597
        let expr = CastExpr::new(expr, target);
9✔
598
        if let Some(valid) = expr.is_valid(self) {
18✔
599
            assert!(valid);
×
600
        }
601
        self.push(Expr::Cast(expr))
4✔
602
    }
603

604
    /// Get an existing expression from its handle.
605
    #[inline]
606
    pub fn get(&self, expr: ExprHandle) -> Option<&Expr> {
14✔
607
        let index = expr.index();
14✔
608
        self.expressions.get(index)
14✔
609
    }
610

611
    /// Get an existing expression from its handle.
612
    #[inline]
613
    pub fn get_mut(&mut self, expr: ExprHandle) -> Option<&mut Expr> {
2✔
614
        let index = expr.index();
2✔
615
        self.expressions.get_mut(index)
2✔
616
    }
617

618
    /// Get an existing expression from its handle.
619
    #[inline]
620
    pub fn try_get(&self, expr: ExprHandle) -> Result<&Expr, ExprError> {
253✔
621
        let index = expr.index();
253✔
622
        self.expressions
253✔
623
            .get(index)
253✔
624
            .ok_or(ExprError::InvalidExprHandleError(format!(
253✔
625
                "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)))
253✔
626
    }
627

628
    /// Get an existing expression from its handle.
629
    #[inline]
630
    pub fn try_get_mut(&mut self, expr: ExprHandle) -> Result<&mut Expr, ExprError> {
2✔
631
        let index = expr.index();
2✔
632
        self.expressions
2✔
633
            .get_mut(index)
2✔
634
            .ok_or(ExprError::InvalidExprHandleError(format!(
2✔
635
                "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✔
636
    }
637

638
    /// Is the expression resulting in a compile-time constant which can be
639
    /// hard-coded into a shader's code?
640
    ///
641
    /// # Panics
642
    ///
643
    /// Panics if `expr` doesn't refer to an expression of this module.
644
    #[inline]
645
    pub fn is_const(&self, expr: ExprHandle) -> bool {
×
646
        let expr = self.get(expr).unwrap();
×
647
        expr.is_const(self)
×
648
    }
649

650
    /// Has the expression any side-effect?
651
    ///
652
    /// Expressions with side-effect need to be stored into temporary variables
653
    /// when the shader code is emitted, so that the side effect is only applied
654
    /// once when the expression is reused in multiple locations.
655
    ///
656
    /// # Panics
657
    ///
658
    /// Panics if `expr` doesn't refer to an expression of this module.
659
    pub fn has_side_effect(&self, expr: ExprHandle) -> bool {
×
660
        let expr = self.get(expr).unwrap();
×
661
        expr.has_side_effect(self)
×
662
    }
663

664
    /// Get the texture layout of this module.
665
    pub fn texture_layout(&self) -> TextureLayout {
25✔
666
        self.texture_layout.clone()
25✔
667
    }
668
}
669

670
/// Errors raised when manipulating expressions [`Expr`] and node graphs
671
/// [`Graph`].
672
///
673
/// [`Graph`]: crate::graph::Graph
674
#[derive(Debug, Clone, PartialEq, Eq, Error)]
675
pub enum ExprError {
676
    /// Expression type error.
677
    ///
678
    /// Generally used for invalid type conversion (casting).
679
    #[error("Type error: {0}")]
680
    TypeError(String),
681

682
    /// Expression syntax error.
683
    #[error("Syntax error: {0}")]
684
    SyntaxError(String),
685

686
    /// Generic graph evaluation error.
687
    #[error("Graph evaluation error: {0}")]
688
    GraphEvalError(String),
689

690
    /// Error resolving a property.
691
    ///
692
    /// An unknown property was not defined in the evaluation context, which
693
    /// usually means that the property was not defined with
694
    /// [`Module::add_property()`].
695
    #[error("Property error: {0}")]
696
    PropertyError(String),
697

698
    /// Invalid expression handle not referencing any existing [`Expr`] in the
699
    /// evaluation [`Module`].
700
    ///
701
    /// This error is commonly raised when using an [`ExprWriter`] and
702
    /// forgetting to transfer the underlying [`Module`] where the expressions
703
    /// are written to the [`EffectAsset`]. See [`ExprWriter`] for details.
704
    ///
705
    /// [`EffectAsset`]: crate::EffectAsset
706
    #[error("Invalid expression handle: {0}")]
707
    InvalidExprHandleError(String),
708

709
    /// Invalid modifier context.
710
    ///
711
    /// The operation was expecting a given [`ModifierContext`], but instead
712
    /// another [`ModifierContext`] was available.
713
    #[error("Invalid modifier context {0}, expected {1} instead.")]
714
    InvalidModifierContext(ModifierContext, ModifierContext),
715
}
716

717
/// Evaluation context for transforming expressions into WGSL code.
718
///
719
/// The evaluation context references a [`Module`] storing all [`Expr`] in use,
720
/// as well as a [`ParticleLayout`] defining the existing attributes of each
721
/// particle and their layout in memory, and a [`PropertyLayout`] defining
722
/// existing properties and their layout in memory. These together define the
723
/// context within which expressions are evaluated.
724
///
725
/// A same expression can be valid in one context and invalid in another. The
726
/// most obvious example is a [`PropertyExpr`] which is only valid if the
727
/// property is actually defined in the property layout of the evaluation
728
/// context.
729
pub trait EvalContext {
730
    /// Get the modifier context of the evaluation.
731
    fn modifier_context(&self) -> ModifierContext;
732

733
    /// Get the particle layout of the effect.
734
    fn particle_layout(&self) -> &ParticleLayout;
735

736
    /// Get the property layout of the effect.
737
    fn property_layout(&self) -> &PropertyLayout;
738

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

748
    /// Generate a unique local variable name.
749
    ///
750
    /// Each time this function is called, a new unique name is generated. The
751
    /// name is guaranteed to be unique within the current evaluation context
752
    /// only. Do not use for global top-level identifiers.
753
    ///
754
    /// The variable name is not registered automatically in the [`Module`]. If
755
    /// you call `make_local_var()` but doesn't use the returned name, it won't
756
    /// appear in the shader.
757
    fn make_local_var(&mut self) -> String;
758

759
    /// Push an intermediate statement during an evaluation.
760
    ///
761
    /// Intermediate statements are inserted before the expression evaluation
762
    /// which produced them. They're generally used to define temporary local
763
    /// variables, for example to store the result of expressions with side
764
    /// effects.
765
    fn push_stmt(&mut self, stmt: &str);
766

767
    /// Create a function.
768
    ///
769
    /// Create a new function with the given `func_name` inside the given
770
    /// [`Module`]. The function takes a list of arguments `args`, which are
771
    /// copied verbatim into the shader code without any validation. The body of
772
    /// the function is generated by invoking the given closure once with the
773
    /// input `module` and a temporary [`EvalContext`] local to the function.
774
    /// The closure must return the generated shader code of the function
775
    /// body. Any statement pushed to the temporary function context with
776
    /// [`EvalContext::push_stmt()`] is emitted inside the function body before
777
    /// the returned code. The function can subsequently be called from the
778
    /// parent context by generating code to call `func_name`, with the correct
779
    /// arguments.
780
    fn make_fn(
781
        &mut self,
782
        func_name: &str,
783
        args: &str,
784
        module: &mut Module,
785
        f: &mut dyn FnMut(&mut Module, &mut dyn EvalContext) -> Result<String, ExprError>,
786
    ) -> Result<(), ExprError>;
787

788
    /// Check if the particle attribute struct is a pointer?
789
    ///
790
    /// In some context the attribute struct (named 'particle' in WGSL code) is
791
    /// a pointer instead of being a struct instance. This happens in particular
792
    /// when defining a function for a modifier, and passing the attribute
793
    /// struct to be modified. In that case the generated code needs to emit
794
    /// a pointer indirection code to access the fields of the struct.
795
    fn is_attribute_pointer(&self) -> bool;
796
}
797

798
/// Language expression producing a value.
799
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
800
pub enum Expr {
801
    /// Built-in expression ([`BuiltInExpr`]).
802
    ///
803
    /// A built-in expression provides access to some internal
804
    /// quantities like the simulation time.
805
    BuiltIn(BuiltInExpr),
806

807
    /// Literal expression ([`LiteralExpr`]).
808
    ///
809
    /// A literal expression represents a shader constants.
810
    Literal(LiteralExpr),
811

812
    /// Property expression ([`PropertyExpr`]).
813
    ///
814
    /// A property expression represents the value of an [`EffectAsset`]'s
815
    /// property.
816
    ///
817
    /// [`EffectAsset`]: crate::EffectAsset
818
    Property(PropertyExpr),
819

820
    /// Attribute expression ([`AttributeExpr`]).
821
    ///
822
    /// An attribute expression represents the value of an attribute for a
823
    /// particle, like its position or velocity.
824
    Attribute(AttributeExpr),
825

826
    /// Attribute expression ([`AttributeExpr`]) from a parent effect.
827
    ///
828
    /// An attribute expression represents the value of an attribute for a
829
    /// particle, like its position or velocity. This attribute however refers
830
    /// to the parent particle which spawned this one, via GPU events.
831
    ///
832
    /// This attribute is only valid when used in init modifiers, from an effect
833
    /// with a parent effect (an effect which has an [`EffectParent`]
834
    /// component).
835
    ///
836
    /// [`EffectParent`]: crate::EffectParent
837
    ParentAttribute(AttributeExpr),
838

839
    /// Unary operation expression.
840
    ///
841
    /// A unary operation transforms an expression into another expression.
842
    Unary {
843
        /// Unary operator.
844
        op: UnaryOperator,
845
        /// Operand the unary operation applies to.
846
        expr: ExprHandle,
847
    },
848

849
    /// Binary operation expression.
850
    ///
851
    /// A binary operation composes two expressions into a third one.
852
    Binary {
853
        /// Binary operator.
854
        op: BinaryOperator,
855
        /// Left-hand side operand the binary operation applies to.
856
        left: ExprHandle,
857
        /// Right-hand side operand the binary operation applies to.
858
        right: ExprHandle,
859
    },
860

861
    /// Ternary operation expression.
862
    ///
863
    /// A ternary operation composes three expressions into a fourth one.
864
    Ternary {
865
        /// Ternary operator.
866
        op: TernaryOperator,
867
        /// First operand the ternary operation applies to.
868
        first: ExprHandle,
869
        /// Second operand the ternary operation applies to.
870
        second: ExprHandle,
871
        /// Third operand the ternary operation applies to.
872
        third: ExprHandle,
873
    },
874

875
    /// Cast expression.
876
    ///
877
    /// An expression to cast an expression to another type.
878
    Cast(CastExpr),
879

880
    /// Access to textures.
881
    ///
882
    /// An expression to sample a texture from the effect's material. Currently
883
    /// only color textures (returning a `vec4<f32>`) are supported.
884
    TextureSample(TextureSampleExpr),
885
}
886

887
impl Expr {
888
    /// Is the expression resulting in a compile-time constant which can be
889
    /// hard-coded into a shader's code?
890
    ///
891
    /// The [`Module`] passed as argument is the owning module of the
892
    /// expression, which is used to recursively evaluate the const-ness of the
893
    /// entire expression. For some expressions like literals or attributes or
894
    /// properties their const-ness is intrinsic to the expression type, but for
895
    /// other expressions like binary operations (addition, ...) their
896
    /// const-ness depends in turn on the const-ness of their sub-expressions
897
    /// (left and right operands), which requires a [`Module`] to be retrieved
898
    /// and evaluated.
899
    ///
900
    /// # Example
901
    ///
902
    /// ```
903
    /// # use bevy_hanabi::*;
904
    /// # let mut module = Module::default();
905
    /// // Literals are always constant by definition.
906
    /// assert!(Expr::Literal(LiteralExpr::new(1.)).is_const(&module));
907
    ///
908
    /// // Properties and attributes are never constant, since they're by definition used
909
    /// // to provide runtime customization.
910
    /// let prop = module.add_property("my_property", 3.0.into());
911
    /// assert!(!Expr::Property(PropertyExpr::new(prop)).is_const(&module));
912
    /// assert!(!Expr::Attribute(AttributeExpr::new(Attribute::POSITION)).is_const(&module));
913
    /// ```
914
    pub fn is_const(&self, module: &Module) -> bool {
×
915
        match self {
×
916
            Expr::BuiltIn(expr) => expr.is_const(),
×
917
            Expr::Literal(expr) => expr.is_const(),
×
918
            Expr::Property(expr) => expr.is_const(),
×
919
            Expr::Attribute(expr) => expr.is_const(),
×
920
            Expr::ParentAttribute(expr) => expr.is_const(),
×
921
            Expr::Unary { expr, .. } => module.is_const(*expr),
×
922
            Expr::Binary { left, right, .. } => module.is_const(*left) && module.is_const(*right),
×
923
            Expr::Ternary {
924
                first,
×
925
                second,
×
926
                third,
×
927
                ..
×
928
            } => module.is_const(*first) && module.is_const(*second) && module.is_const(*third),
×
929
            Expr::Cast(expr) => module.is_const(expr.inner),
×
930
            Expr::TextureSample(_) => false,
×
931
        }
932
    }
933

934
    /// Has the expression any side-effect?
935
    ///
936
    /// Expressions with side-effect need to be stored into temporary variables
937
    /// when the shader code is emitted, so that the side effect is only applied
938
    /// once when the expression is reused in multiple locations.
939
    pub fn has_side_effect(&self, module: &Module) -> bool {
×
940
        match self {
×
941
            Expr::BuiltIn(expr) => expr.has_side_effect(),
×
942
            Expr::Literal(_) => false,
×
943
            Expr::Property(_) => false,
×
944
            Expr::Attribute(_) => false,
×
945
            Expr::ParentAttribute(_) => false,
×
946
            Expr::Unary { expr, .. } => module.has_side_effect(*expr),
×
947
            Expr::Binary { left, right, op } => {
×
948
                (*op == BinaryOperator::UniformRand || *op == BinaryOperator::NormalRand)
×
949
                    || module.has_side_effect(*left)
×
950
                    || module.has_side_effect(*right)
×
951
            }
952
            Expr::Ternary {
953
                first,
×
954
                second,
×
955
                third,
×
956
                ..
×
957
            } => {
×
958
                module.has_side_effect(*first)
×
959
                    || module.has_side_effect(*second)
×
960
                    || module.has_side_effect(*third)
×
961
            }
962
            Expr::Cast(expr) => module.has_side_effect(expr.inner),
×
963
            Expr::TextureSample(_) => false,
×
964
        }
965
    }
966

967
    /// The type of the value produced by the expression.
968
    ///
969
    /// If the type is variable and depends on the runtime evaluation context,
970
    /// this returns `None`. In that case the type needs to be obtained by
971
    /// evaluating the expression with [`eval()`].
972
    ///
973
    /// # Example
974
    ///
975
    /// ```
976
    /// # use bevy_hanabi::*;
977
    /// // Literal expressions always have a constant, build-time value type.
978
    /// let expr = Expr::Literal(LiteralExpr::new(1.));
979
    /// assert_eq!(
980
    ///     expr.value_type(),
981
    ///     Some(ValueType::Scalar(ScalarType::Float))
982
    /// );
983
    /// ```
984
    ///
985
    /// [`eval()`]: crate::graph::Expr::eval
986
    pub fn value_type(&self) -> Option<ValueType> {
21✔
987
        match self {
21✔
988
            Expr::BuiltIn(expr) => Some(expr.value_type()),
×
989
            Expr::Literal(expr) => Some(expr.value_type()),
17✔
990
            Expr::Property(_) => None,
1✔
991
            Expr::Attribute(expr) => Some(expr.value_type()),
3✔
992
            Expr::ParentAttribute(expr) => Some(expr.value_type()),
×
993
            Expr::Unary { .. } => None,
×
994
            Expr::Binary { .. } => None,
×
995
            Expr::Ternary { .. } => None,
×
996
            Expr::Cast(expr) => Some(expr.value_type()),
×
997
            Expr::TextureSample(expr) => Some(expr.value_type()),
×
998
        }
999
    }
1000

1001
    /// Evaluate the expression in the given context.
1002
    ///
1003
    /// Evaluate the full expression as part of the given evaluation context,
1004
    /// returning the WGSL string representation of the expression on success.
1005
    ///
1006
    /// The evaluation context is used to resolve some quantities related to the
1007
    /// effect asset, like its properties. It also holds the [`Module`] that the
1008
    /// expression is part of, to allow resolving sub-expressions of operators.
1009
    ///
1010
    /// # Example
1011
    ///
1012
    /// ```
1013
    /// # use bevy_hanabi::*;
1014
    /// let mut module = Module::default();
1015
    /// # let pl = PropertyLayout::empty();
1016
    /// # let pal = ParticleLayout::default();
1017
    /// # let mut context = ShaderWriter::new(ModifierContext::Update, &pl, &pal);
1018
    /// let handle = module.lit(1.);
1019
    /// let expr = module.get(handle).unwrap();
1020
    /// assert_eq!(Ok("1.".to_string()), expr.eval(&module, &mut context));
1021
    /// ```
1022
    pub fn eval(
242✔
1023
        &self,
1024
        module: &Module,
1025
        context: &mut dyn EvalContext,
1026
    ) -> Result<String, ExprError> {
1027
        match self {
242✔
1028
            Expr::BuiltIn(expr) => expr.eval(context),
34✔
1029
            Expr::Literal(expr) => expr.eval(context),
96✔
1030
            Expr::Property(expr) => expr.eval(module, context),
2✔
1031
            Expr::Attribute(expr) => expr.eval(context, false),
26✔
1032
            Expr::ParentAttribute(expr) => expr.eval(context, true),
×
1033
            Expr::Unary { op, expr } => {
38✔
1034
                // Recursively evaluate child expressions throught the context to ensure caching
1035
                let expr = context.eval(module, *expr)?;
76✔
1036

1037
                // if expr.value_type() != self.value_type() {
1038
                //     return Err(ExprError::TypeError(format!(
1039
                //         "Cannot apply normalize() function to non-vector expression: {}",
1040
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1041
                //     )));
1042
                // }
1043

1044
                Ok(if op.is_functional() {
1045
                    format!("{}({})", op.to_wgsl_string(), expr)
34✔
1046
                } else {
1047
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1048
                })
1049
            }
1050
            Expr::Binary { op, left, right } => {
39✔
1051
                // Recursively evaluate child expressions throught the context to ensure caching
1052
                let compiled_left = context.eval(module, *left)?;
78✔
1053
                let compiled_right = context.eval(module, *right)?;
39✔
1054

1055
                // if !self.input.value_type().is_vector() {
1056
                //     return Err(ExprError::TypeError(format!(
1057
                //         "Cannot apply normalize() function to non-vector expression: {}",
1058
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1059
                //     )));
1060
                // }
1061

1062
                if op.is_functional() {
1063
                    if op.needs_type_suffix() {
12✔
1064
                        let lhs_type = module.get(*left).and_then(|arg| arg.value_type());
×
1065
                        let rhs_type = module.get(*right).and_then(|arg| arg.value_type());
×
1066
                        if lhs_type.is_none() || rhs_type.is_none() {
×
1067
                            return Err(ExprError::TypeError(
×
1068
                                "Can't determine the type of the operand".to_string(),
×
1069
                            ));
1070
                        }
1071
                        if lhs_type != rhs_type {
×
1072
                            return Err(ExprError::TypeError("Mismatched types".to_string()));
×
1073
                        }
1074
                        let value_type = lhs_type.unwrap();
×
1075
                        let suffix = match value_type {
×
1076
                            ValueType::Scalar(ScalarType::Float) => "f",
×
1077
                            ValueType::Vector(vector_type)
×
1078
                                if vector_type.elem_type() == ScalarType::Float =>
×
1079
                            {
1080
                                match vector_type.count() {
×
1081
                                    2 => "vec2",
×
1082
                                    3 => "vec3",
×
1083
                                    4 => "vec4",
×
1084
                                    _ => unreachable!(),
1085
                                }
1086
                            }
1087
                            _ => {
1088
                                // Add more types here as needed.
1089
                                return Err(ExprError::TypeError("Unsupported type".to_string()));
×
1090
                            }
1091
                        };
1092

1093
                        Ok(format!(
1094
                            "{}_{}({}, {})",
1095
                            op.to_wgsl_string(),
1096
                            suffix,
1097
                            compiled_left,
1098
                            compiled_right
1099
                        ))
1100
                    } else {
1101
                        Ok(format!(
12✔
1102
                            "{}({}, {})",
12✔
1103
                            op.to_wgsl_string(),
12✔
1104
                            compiled_left,
12✔
1105
                            compiled_right
12✔
1106
                        ))
1107
                    }
1108
                } else {
1109
                    Ok(format!(
27✔
1110
                        "({}) {} ({})",
27✔
1111
                        compiled_left,
27✔
1112
                        op.to_wgsl_string(),
27✔
1113
                        compiled_right
27✔
1114
                    ))
1115
                }
1116
            }
1117
            Expr::Ternary {
1118
                op,
3✔
1119
                first,
3✔
1120
                second,
3✔
1121
                third,
3✔
1122
            } => {
1123
                // Recursively evaluate child expressions throught the context to ensure caching
1124
                let first = context.eval(module, *first)?;
6✔
1125
                let second = context.eval(module, *second)?;
3✔
1126
                let third = context.eval(module, *third)?;
3✔
1127

1128
                // if !self.input.value_type().is_vector() {
1129
                //     return Err(ExprError::TypeError(format!(
1130
                //         "Cannot apply normalize() function to non-vector expression: {}",
1131
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1132
                //     )));
1133
                // }
1134

1135
                Ok(format!(
1136
                    "{}({}, {}, {})",
1137
                    op.to_wgsl_string(),
1138
                    first,
1139
                    second,
1140
                    third
1141
                ))
1142
            }
1143
            Expr::Cast(expr) => {
4✔
1144
                // Recursively evaluate child expressions throught the context to ensure caching
1145
                let inner = context.eval(module, expr.inner)?;
8✔
1146

1147
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
1148
            }
1149
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1150
        }
1151
    }
1152
}
1153

1154
/// A literal constant expression like `3.0` or `vec3<f32>(1.0, 2.0, 3.0)`.
1155
///
1156
/// Literal expression are compile-time constants. They are always constant
1157
/// ([`is_const()`] is `true`) and have a value type equal to the type of the
1158
/// constant itself.
1159
///
1160
/// [`is_const()`]: LiteralExpr::is_const
1161
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
1162
#[serde(transparent)]
1163
pub struct LiteralExpr {
1164
    value: Value,
1165
}
1166

1167
impl LiteralExpr {
1168
    /// Create a new literal expression from a [`Value`].
1169
    pub fn new<V>(value: V) -> Self
76✔
1170
    where
1171
        Value: From<V>,
1172
    {
1173
        Self {
1174
            value: value.into(),
76✔
1175
        }
1176
    }
1177

1178
    /// Is the expression resulting in a compile-time constant which can be
1179
    /// hard-coded into a shader's code?
1180
    pub fn is_const(&self) -> bool {
×
1181
        true
×
1182
    }
1183

1184
    /// Get the value type of the expression.
1185
    pub fn value_type(&self) -> ValueType {
17✔
1186
        self.value.value_type()
17✔
1187
    }
1188

1189
    /// Evaluate the expression in the given context.
1190
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
96✔
1191
        Ok(self.value.to_wgsl_string())
96✔
1192
    }
1193
}
1194

1195
impl ToWgslString for LiteralExpr {
1196
    fn to_wgsl_string(&self) -> String {
×
1197
        self.value.to_wgsl_string()
×
1198
    }
1199
}
1200

1201
impl From<&Value> for LiteralExpr {
1202
    fn from(value: &Value) -> Self {
×
1203
        Self { value: *value }
×
1204
    }
1205
}
1206

1207
impl<T: Into<Value>> From<T> for LiteralExpr {
1208
    fn from(value: T) -> Self {
×
1209
        Self {
1210
            value: value.into(),
×
1211
        }
1212
    }
1213
}
1214

1215
/// Expression representing the value of an attribute of a particle.
1216
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1217
pub struct AttributeExpr {
1218
    attr: Attribute,
1219
}
1220

1221
impl AttributeExpr {
1222
    /// Create a new attribute expression.
1223
    #[inline]
1224
    pub fn new(attr: Attribute) -> Self {
27✔
1225
        Self { attr }
1226
    }
1227

1228
    /// Is the expression resulting in a compile-time constant which can be
1229
    /// hard-coded into a shader's code?
1230
    pub fn is_const(&self) -> bool {
×
1231
        false
×
1232
    }
1233

1234
    /// Get the value type of the expression.
1235
    pub fn value_type(&self) -> ValueType {
3✔
1236
        self.attr.value_type()
3✔
1237
    }
1238

1239
    /// Evaluate the expression in the given context.
1240
    pub fn eval(&self, context: &dyn EvalContext, parent: bool) -> Result<String, ExprError> {
26✔
1241
        if self.attr == Attribute::ID {
26✔
1242
            // Pseudo-attribute, not stored in the particle buffer
1243
            Ok(if parent {
×
1244
                "parent_particle_index"
×
1245
            } else {
1246
                "particle_index"
×
1247
            }
1248
            .to_string())
×
1249
        } else if self.attr == Attribute::PARTICLE_COUNTER {
26✔
1250
            // Pseudo-attribute, not stored in the particle buffer
1251
            Ok("particle_counter".to_string())
×
1252
        } else {
1253
            let owner = if parent {
26✔
1254
                "parent_particle"
×
1255
            } else {
1256
                "particle"
26✔
1257
            };
1258
            if context.is_attribute_pointer() {
1259
                Ok(format!("(*{}).{}", owner, self.attr.name()))
2✔
1260
            } else {
1261
                Ok(format!("{}.{}", owner, self.attr.name()))
24✔
1262
            }
1263
        }
1264
    }
1265
}
1266

1267
impl ToWgslString for AttributeExpr {
1268
    fn to_wgsl_string(&self) -> String {
×
1269
        format!("particle.{}", self.attr.name())
×
1270
    }
1271
}
1272

1273
impl From<Attribute> for AttributeExpr {
1274
    fn from(value: Attribute) -> Self {
×
1275
        AttributeExpr::new(value)
×
1276
    }
1277
}
1278

1279
/// Expression representing the value of a property of an effect.
1280
///
1281
/// A property expression represents the value of the property at the time the
1282
/// expression appears. In shader, the expression yields a read from the
1283
/// property memory location.
1284
///
1285
/// To create a property to reference with an expression, use
1286
/// [`Module::add_property()`].
1287
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1288
#[repr(transparent)]
1289
#[serde(transparent)]
1290
pub struct PropertyExpr {
1291
    property: PropertyHandle,
1292
}
1293

1294
impl PropertyExpr {
1295
    /// Create a new property expression.
1296
    #[inline]
1297
    pub fn new(property: PropertyHandle) -> Self {
4✔
1298
        Self { property }
1299
    }
1300

1301
    /// Is the expression resulting in a compile-time constant which can be
1302
    /// hard-coded into a shader's code?
1303
    fn is_const(&self) -> bool {
×
1304
        false
×
1305
    }
1306

1307
    /// Evaluate the expression in the given context.
1308
    fn eval(&self, module: &Module, context: &dyn EvalContext) -> Result<String, ExprError> {
2✔
1309
        let prop = module
4✔
1310
            .get_property(self.property)
2✔
1311
            .ok_or(ExprError::PropertyError(format!(
2✔
1312
                "Unknown property handle {:?} in evaluation module.",
2✔
1313
                self.property
2✔
1314
            )))?;
1315
        if !context.property_layout().contains(prop.name()) {
1316
            return Err(ExprError::PropertyError(format!(
×
1317
                "Unknown property '{}' in evaluation layout.",
×
1318
                prop.name()
×
1319
            )));
1320
        }
1321

1322
        Ok(format!("properties.{}", prop.name()))
2✔
1323
    }
1324
}
1325

1326
/// Expression to cast an expression to another type.
1327
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1328
pub struct CastExpr {
1329
    /// The operand expression to cast.
1330
    inner: ExprHandle,
1331
    /// The target type to cast to.
1332
    target: ValueType,
1333
}
1334

1335
impl CastExpr {
1336
    /// Create a new cast expression.
1337
    #[inline]
1338
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1339
        Self {
1340
            inner,
1341
            target: target.into(),
12✔
1342
        }
1343
    }
1344

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

1350
    /// Try to evaluate if the cast expression is valid.
1351
    ///
1352
    /// The evaluation fails if the value type of the operand cannot be
1353
    /// determined. In that case, the function returns `None`.
1354
    ///
1355
    /// Valid cast expressions are:
1356
    /// - scalar to scalar
1357
    /// - scalar to vector
1358
    /// - vector to vector
1359
    /// - matrix to matrix
1360
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
12✔
1361
        let Some(inner) = module.get(self.inner) else {
24✔
1362
            return Some(false);
×
1363
        };
1364
        if let Some(inner_type) = inner.value_type() {
11✔
1365
            match self.target {
1366
                ValueType::Scalar(_) => {
1367
                    // scalar -> scalar only
1368
                    Some(matches!(inner_type, ValueType::Scalar(_)))
8✔
1369
                }
1370
                ValueType::Vector(_) => {
1371
                    // {scalar, vector} -> vector
1372
                    Some(!matches!(inner_type, ValueType::Matrix(_)))
7✔
1373
                }
1374
                ValueType::Matrix(_) => {
1375
                    // matrix -> matrix only
1376
                    Some(matches!(inner_type, ValueType::Matrix(_)))
4✔
1377
                }
1378
            }
1379
        } else {
1380
            None
1✔
1381
        }
1382
    }
1383
}
1384

1385
/// Expression to sample a texture from the effect's material.
1386
///
1387
/// This currently supports only 4-component textures sampled with [the WGSL
1388
/// `textureSample()` function], that is all textures which return a `vec4<f32>`
1389
/// when sampled. This is the case of most color textures, including
1390
/// single-channel (e.g. red) textures which return zero for missing components,
1391
/// but excludes depth textures.
1392
///
1393
/// [the WGSL `textureSample()` function]: https://www.w3.org/TR/WGSL/#texturesample
1394
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1395
pub struct TextureSampleExpr {
1396
    /// The index of the image to sample. This is the texture slot defined in
1397
    /// the [`Module`]. The texture bound to the slot is defined in the
1398
    /// [`EffectMaterial`] component.
1399
    ///
1400
    /// [`EffectMaterial`]: crate::EffectMaterial
1401
    pub image: ExprHandle,
1402
    /// The coordinates to sample at.
1403
    pub coordinates: ExprHandle,
1404
}
1405

1406
impl TextureSampleExpr {
1407
    /// Create a new texture sample expression.
1408
    #[inline]
1409
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1410
        Self { image, coordinates }
1411
    }
1412

1413
    /// Get the value type of the expression.
1414
    pub fn value_type(&self) -> ValueType {
×
1415
        // FIXME - depth textures return a single f32 when sampled
1416
        ValueType::Vector(VectorType::VEC4F)
×
1417
    }
1418

1419
    /// Try to evaluate if the texture sample expression is valid.
1420
    ///
1421
    /// This only checks that the expressions exist in the module.
1422
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
×
1423
        let Some(_image) = module.get(self.image) else {
×
1424
            return Some(false);
×
1425
        };
1426
        let Some(_coordinates) = module.get(self.coordinates) else {
×
1427
            return Some(false);
×
1428
        };
1429
        Some(true)
1430
    }
1431

1432
    /// Evaluate the expression in the given context.
1433
    pub fn eval(
×
1434
        &self,
1435
        module: &Module,
1436
        context: &mut dyn EvalContext,
1437
    ) -> Result<String, ExprError> {
1438
        let image = module.try_get(self.image)?;
×
1439
        let image = image.eval(module, context)?;
×
1440
        let coordinates = module.try_get(self.coordinates)?;
×
1441
        let coordinates = coordinates.eval(module, context)?;
×
1442
        Ok(format!(
1443
            "textureSample(material_texture_{image}, material_sampler_{image}, {coordinates})",
1444
        ))
1445
    }
1446
}
1447

1448
/// Built-in operators.
1449
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1450
pub enum BuiltInOperator {
1451
    /// Current effect system simulation time since startup, in seconds.
1452
    ///
1453
    /// This is based on the
1454
    /// [`Time<EffectSimulation>`](crate::time::EffectSimulation) clock.
1455
    ///
1456
    /// Type: `f32`
1457
    Time,
1458
    /// Delta time, in seconds, since last effect system update.
1459
    ///
1460
    /// Type: `f32`
1461
    DeltaTime,
1462
    /// Current virtual time since startup, in seconds.
1463
    ///
1464
    /// This is based on the [`Time<Virtual>`](bevy::time::Virtual) clock.
1465
    ///
1466
    /// Type: `f32`
1467
    VirtualTime,
1468
    /// Virtual delta time, in seconds, since last effect system update.
1469
    ///
1470
    /// Type: `f32`
1471
    VirtualDeltaTime,
1472
    /// Current real time since startup, in seconds.
1473
    ///
1474
    /// This is based on the [`Time<Time>`](bevy::time::Real) clock.
1475
    ///
1476
    /// Type: `f32`
1477
    RealTime,
1478
    /// Real delta time, in seconds, since last effect system update.
1479
    ///
1480
    /// Type: `f32`
1481
    RealDeltaTime,
1482
    /// Random unit value of the given type.
1483
    ///
1484
    /// The type can be any scalar or vector type. Matrix types are not
1485
    /// supported. The random values generated are uniformly distributed in
1486
    /// `[0:1]`. For vectors, each component is sampled separately.
1487
    ///
1488
    /// The random number generator is from [the PCG family] of PRNGs, and is
1489
    /// implemented directly inside the shader, and running on the GPU
1490
    /// exclusively. It's seeded by the [`SpawnerSettings`].
1491
    ///
1492
    /// Type: Same as its [`ValueType`].
1493
    ///
1494
    /// [the PCG family]: https://www.pcg-random.org/
1495
    /// [`SpawnerSettings`]: crate::SpawnerSettings
1496
    Rand(ValueType),
1497
    /// Value of the alpha cutoff for alpha masking.
1498
    ///
1499
    /// This value is only available in the render context. It represents the
1500
    /// current threshold, generally in \[0:1\], which the particle's fragment
1501
    /// alpha value will be compared against to determine alpha masking.
1502
    ///
1503
    /// The value is initalized at the beginning of the fragment shader to the
1504
    /// expression stored in [`AlphaMode::Mask`].
1505
    ///
1506
    /// Type: `f32`
1507
    ///
1508
    /// [`AlphaMode::Mask`]: crate::AlphaMode::Mask
1509
    AlphaCutoff,
1510
    /// Alive flag for the particle.
1511
    ///
1512
    /// The alive flag is initialized at the beginning of the update pass:
1513
    /// - If the particle has both the [`Attribute::AGE`] and
1514
    ///   [`Attribute::LIFETIME`], then the initial value at the beginning of
1515
    ///   the update pass is `age < lifetime`.
1516
    /// - Otherwise, the initial value is `true`.
1517
    ///
1518
    /// At the end of the update pass, if the particle has both the
1519
    /// [`Attribute::AGE`] and [`Attribute::LIFETIME`], then the flag is
1520
    /// re-evaluated as:
1521
    ///
1522
    /// ```wgsl
1523
    /// is_alive = is_alive && (particle.age < particle.lifetime);
1524
    /// ```
1525
    ///
1526
    /// If the flag is `false` after that, the particle is considered dead and
1527
    /// it's deallocated.
1528
    ///
1529
    /// This flag is only available in the update pass. Attempting to use it
1530
    /// inside either the init or render passes will generate an invalid shader.
1531
    ///
1532
    /// Type: `bool`
1533
    IsAlive,
1534
}
1535

1536
impl BuiltInOperator {
1537
    /// Get the operator name.
1538
    pub fn name(&self) -> &str {
49✔
1539
        match self {
49✔
1540
            BuiltInOperator::Time => "time",
6✔
1541
            BuiltInOperator::DeltaTime => "delta_time",
13✔
1542
            BuiltInOperator::VirtualTime => "virtual_time",
2✔
1543
            BuiltInOperator::VirtualDeltaTime => "virtual_delta_time",
2✔
1544
            BuiltInOperator::RealTime => "real_time",
2✔
1545
            BuiltInOperator::RealDeltaTime => "real_delta_time",
2✔
1546
            BuiltInOperator::Rand(value_type) => match value_type {
22✔
1547
                ValueType::Scalar(s) => match s {
10✔
1548
                    ScalarType::Bool => "brand",
1✔
1549
                    ScalarType::Float => "frand",
7✔
1550
                    ScalarType::Int => "irand",
1✔
1551
                    ScalarType::Uint => "urand",
1✔
1552
                },
1553
                ValueType::Vector(vector_type) => {
12✔
1554
                    match (vector_type.elem_type(), vector_type.count()) {
12✔
1555
                        (ScalarType::Bool, 2) => "brand2",
1✔
1556
                        (ScalarType::Bool, 3) => "brand3",
1✔
1557
                        (ScalarType::Bool, 4) => "brand4",
1✔
1558
                        (ScalarType::Float, 2) => "frand2",
1✔
1559
                        (ScalarType::Float, 3) => "frand3",
1✔
1560
                        (ScalarType::Float, 4) => "frand4",
1✔
1561
                        (ScalarType::Int, 2) => "irand2",
1✔
1562
                        (ScalarType::Int, 3) => "irand3",
1✔
1563
                        (ScalarType::Int, 4) => "irand4",
1✔
1564
                        (ScalarType::Uint, 2) => "urand2",
1✔
1565
                        (ScalarType::Uint, 3) => "urand3",
1✔
1566
                        (ScalarType::Uint, 4) => "urand4",
1✔
1567
                        _ => panic!("Invalid vector type {:?}", vector_type),
×
1568
                    }
1569
                }
1570
                ValueType::Matrix(_) => panic!("Invalid BuiltInOperator::Rand(ValueType::Matrix)."),
×
1571
            },
1572
            BuiltInOperator::AlphaCutoff => "alpha_cutoff",
×
1573
            BuiltInOperator::IsAlive => "is_alive",
×
1574
        }
1575
    }
1576

1577
    /// Get the type of the value of a built-in operator.
1578
    pub fn value_type(&self) -> ValueType {
4✔
1579
        match self {
4✔
1580
            BuiltInOperator::Time => ValueType::Scalar(ScalarType::Float),
2✔
1581
            BuiltInOperator::DeltaTime => ValueType::Scalar(ScalarType::Float),
2✔
1582
            BuiltInOperator::VirtualTime => ValueType::Scalar(ScalarType::Float),
×
1583
            BuiltInOperator::VirtualDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1584
            BuiltInOperator::RealTime => ValueType::Scalar(ScalarType::Float),
×
1585
            BuiltInOperator::RealDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1586
            BuiltInOperator::Rand(value_type) => *value_type,
×
1587
            BuiltInOperator::AlphaCutoff => ValueType::Scalar(ScalarType::Float),
×
1588
            BuiltInOperator::IsAlive => ValueType::Scalar(ScalarType::Bool),
×
1589
        }
1590
    }
1591

1592
    // /// Evaluate the result of the operator as an expression.
1593
    // pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
1594
    //     match self {
1595
    //         BuiltInOperator::Time => Value::Scalar(Scal)
1596
    //     }
1597
    // }
1598
}
1599

1600
impl ToWgslString for BuiltInOperator {
1601
    fn to_wgsl_string(&self) -> String {
37✔
1602
        match self {
37✔
1603
            BuiltInOperator::Rand(_) => format!("{}()", self.name()),
22✔
1604
            BuiltInOperator::IsAlive => "is_alive".to_string(),
1✔
1605
            _ => format!("sim_params.{}", self.name()),
14✔
1606
        }
1607
    }
1608
}
1609

1610
/// Expression for getting built-in quantities related to the effect system.
1611
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1612
pub struct BuiltInExpr {
1613
    operator: BuiltInOperator,
1614
}
1615

1616
impl BuiltInExpr {
1617
    /// Create a new built-in operator expression.
1618
    ///
1619
    /// # Panics
1620
    ///
1621
    /// Panics on invalid [`BuiltInOperator`], like `Rand(MatrixType)`. See
1622
    /// each [`BuiltInOperator`] variant for more details.
1623
    #[inline]
1624
    pub fn new(operator: BuiltInOperator) -> Self {
33✔
1625
        if let BuiltInOperator::Rand(value_type) = operator {
51✔
1626
            assert!(!matches!(value_type, ValueType::Matrix(_)));
18✔
1627
        }
1628
        Self { operator }
1629
    }
1630

1631
    /// Is the expression resulting in a compile-time constant?
1632
    ///
1633
    /// Constant expressions can be hard-coded into a shader's code, making them
1634
    /// more efficient and open to shader compiler optimizing.
1635
    pub fn is_const(&self) -> bool {
×
1636
        false
×
1637
    }
1638

1639
    /// Has the expression any side-effect?
1640
    ///
1641
    /// Expressions with side-effect need to be stored into temporary variables
1642
    /// when the shader code is emitted, so that the side effect is only applied
1643
    /// once when the expression is reused in multiple locations.
1644
    pub fn has_side_effect(&self) -> bool {
37✔
1645
        matches!(self.operator, BuiltInOperator::Rand(_))
52✔
1646
    }
1647

1648
    /// Get the value type of the expression.
1649
    ///
1650
    /// The value type of the expression is the type of the value(s) that an
1651
    /// expression produces.
1652
    pub fn value_type(&self) -> ValueType {
×
1653
        self.operator.value_type()
×
1654
    }
1655

1656
    /// Evaluate the expression in the given context.
1657
    pub fn eval(&self, context: &mut dyn EvalContext) -> Result<String, ExprError> {
37✔
1658
        if self.has_side_effect() {
37✔
1659
            let var_name = context.make_local_var();
22✔
1660
            context.push_stmt(&format!("let {} = {};", var_name, self.to_wgsl_string()));
22✔
1661
            Ok(var_name)
22✔
1662
        } else {
1663
            Ok(self.to_wgsl_string())
15✔
1664
        }
1665
    }
1666
}
1667

1668
impl ToWgslString for BuiltInExpr {
1669
    fn to_wgsl_string(&self) -> String {
37✔
1670
        self.operator.to_wgsl_string()
37✔
1671
    }
1672
}
1673

1674
/// Unary operator.
1675
///
1676
/// Operator applied to a single operand to produce another value. The type of
1677
/// the operand and the result are not necessarily the same. Valid operand types
1678
/// depend on the operator itself.
1679
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1680
pub enum UnaryOperator {
1681
    /// Absolute value operator.
1682
    ///
1683
    /// Return the absolute value of the operand, component-wise for vectors.
1684
    /// Only valid for numeric operands.
1685
    Abs,
1686

1687
    /// Inverse cosine operator.
1688
    ///
1689
    /// Return the inverse cosine of the operand, component-wise for vectors.
1690
    /// Only valid for floating-point operands.
1691
    Acos,
1692

1693
    /// Inverse sine operator.
1694
    ///
1695
    /// Return the inverse sine of the operand, component-wise for vectors.
1696
    /// Only valid for floating-point operands.
1697
    Asin,
1698

1699
    /// Inverse tangent operator.
1700
    ///
1701
    /// Return the inverse tangent of the operand, component-wise for vectors.
1702
    /// Only valid for floating-point operands.
1703
    Atan,
1704

1705
    /// Logical ALL operator for bool vectors.
1706
    ///
1707
    /// Return `true` if all the components of the bool vector operand are
1708
    /// `true`. Invalid for any other type of operand.
1709
    All,
1710

1711
    /// Logical ANY operator for bool vectors.
1712
    ///
1713
    /// Return `true` if any component of the bool vector operand is `true`.
1714
    /// Invalid for any other type of operand.
1715
    Any,
1716

1717
    /// Ceiling operator.
1718
    ///
1719
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1720
    /// `x` is the operand which the operator applies to.
1721
    Ceil,
1722

1723
    /// Cosine operator.
1724
    Cos,
1725

1726
    /// Natural exponent operator.
1727
    ///
1728
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1729
    /// for vectors.
1730
    Exp,
1731

1732
    /// Base-2 exponent operator.
1733
    ///
1734
    /// Return two raised to the power of the operand (`2^x`), component-wise
1735
    /// for vectors.
1736
    Exp2,
1737

1738
    /// Floor operator.
1739
    ///
1740
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1741
    /// `x` is the operand which the operator applies to.
1742
    Floor,
1743

1744
    /// Fractional part operator.
1745
    ///
1746
    /// Return the fractional part of the operand, which is equal to `x -
1747
    /// floor(x)`, component-wise for vectors.
1748
    Fract,
1749

1750
    /// Inverse square root operator.
1751
    ///
1752
    /// Return the inverse square root of the floating-point operand (`1.0 /
1753
    /// sqrt(x)`), component-wise for vectors.
1754
    InvSqrt,
1755

1756
    /// Length operator.
1757
    ///
1758
    /// Return the length of a floating point scalar or vector. The "length" of
1759
    /// a scalar is taken as its absolute value. The length of a vector is the
1760
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1761
    /// squared components).
1762
    ///
1763
    /// The output is always a floating point scalar.
1764
    Length,
1765

1766
    /// Natural logarithm operator.
1767
    ///
1768
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1769
    /// for vectors.
1770
    Log,
1771

1772
    /// Base-2 logarithm operator.
1773
    ///
1774
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1775
    /// for vectors.
1776
    Log2,
1777

1778
    /// Vector normalizing operator.
1779
    ///
1780
    /// Normalize the given numeric vector. Only valid for numeric vector
1781
    /// operands.
1782
    Normalize,
1783

1784
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1785
    ///
1786
    /// Convert the four components of a signed normalized floating point vector
1787
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1788
    /// four values into a single `u32`. Each vector component should be in
1789
    /// `[-1:1]` before packing; values outside this range are clamped.
1790
    Pack4x8snorm,
1791

1792
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1793
    ///
1794
    /// Convert the four components of an unsigned normalized floating point
1795
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1796
    /// those four values into a single `u32`. Each vector component should
1797
    /// be in `[0:1]` before packing; values outside this range are clamped.
1798
    Pack4x8unorm,
1799

1800
    /// Rounding operator.
1801
    ///
1802
    /// Round the given scalar of vector float to the nearest integer, returned
1803
    /// as a float value.
1804
    Round,
1805

1806
    /// Saturate operator.
1807
    ///
1808
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1809
    /// vectors.
1810
    Saturate,
1811

1812
    /// Sign operator.
1813
    ///
1814
    /// Return a value representing the sign of a floating point scalar or
1815
    /// vector input:
1816
    /// - `1.` if the operand is > 0
1817
    /// - `0.` if the operand is = 0
1818
    /// - `-1.` if the operand is < 0
1819
    ///
1820
    /// Applies component-wise for vectors.
1821
    Sign,
1822

1823
    /// Sine operator.
1824
    Sin,
1825

1826
    /// Square root operator.
1827
    ///
1828
    /// Return the square root of the floating-point operand, component-wise for
1829
    /// vectors.
1830
    Sqrt,
1831

1832
    /// Tangent operator.
1833
    Tan,
1834

1835
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1836
    ///
1837
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1838
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1839
    Unpack4x8snorm,
1840

1841
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1842
    ///
1843
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1844
    /// then convert each value to an unsigned normalized `f32` value in
1845
    /// `[0:1]`.
1846
    Unpack4x8unorm,
1847

1848
    /// Get the fourth component of a vector.
1849
    ///
1850
    /// This is only valid for vectors of rank 4.
1851
    W,
1852

1853
    /// Get the first component of a scalar or vector.
1854
    ///
1855
    /// For scalar, return the value itself. For vectors, return the first
1856
    /// component.
1857
    X,
1858

1859
    /// Get the second component of a vector.
1860
    Y,
1861

1862
    /// Get the third component of a vector.
1863
    ///
1864
    /// This is only valid for vectors of rank 3 or more.
1865
    Z,
1866
}
1867

1868
impl UnaryOperator {
1869
    /// Check if a unary operator is called via a functional-style call.
1870
    ///
1871
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
1872
    /// example, while non-functional ones are in the form `inner.op`,
1873
    /// like `v.x` for example. This check is used for formatting the WGSL
1874
    /// code emitted during evaluation of a binary operation expression.
1875
    pub fn is_functional(&self) -> bool {
38✔
1876
        !matches!(
34✔
1877
            *self,
38✔
1878
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
1879
        )
1880
    }
1881
}
1882

1883
impl ToWgslString for UnaryOperator {
1884
    fn to_wgsl_string(&self) -> String {
38✔
1885
        match *self {
38✔
1886
            UnaryOperator::Abs => "abs".to_string(),
5✔
1887
            UnaryOperator::Acos => "acos".to_string(),
1✔
1888
            UnaryOperator::Asin => "asin".to_string(),
1✔
1889
            UnaryOperator::Atan => "atan".to_string(),
1✔
1890
            UnaryOperator::All => "all".to_string(),
1✔
1891
            UnaryOperator::Any => "any".to_string(),
3✔
1892
            UnaryOperator::Ceil => "ceil".to_string(),
1✔
1893
            UnaryOperator::Cos => "cos".to_string(),
1✔
1894
            UnaryOperator::Exp => "exp".to_string(),
1✔
1895
            UnaryOperator::Exp2 => "exp2".to_string(),
1✔
1896
            UnaryOperator::Floor => "floor".to_string(),
1✔
1897
            UnaryOperator::Fract => "fract".to_string(),
1✔
1898
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
1✔
1899
            UnaryOperator::Length => "length".to_string(),
1✔
1900
            UnaryOperator::Log => "log".to_string(),
1✔
1901
            UnaryOperator::Log2 => "log2".to_string(),
1✔
1902
            UnaryOperator::Normalize => "normalize".to_string(),
2✔
1903
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
1✔
1904
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
1✔
1905
            UnaryOperator::Round => "round".to_string(),
1✔
1906
            UnaryOperator::Saturate => "saturate".to_string(),
1✔
1907
            UnaryOperator::Sign => "sign".to_string(),
1✔
1908
            UnaryOperator::Sin => "sin".to_string(),
1✔
1909
            UnaryOperator::Sqrt => "sqrt".to_string(),
1✔
1910
            UnaryOperator::Tan => "tan".to_string(),
1✔
1911
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
1✔
1912
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
1✔
1913
            UnaryOperator::W => "w".to_string(),
1✔
1914
            UnaryOperator::X => "x".to_string(),
1✔
1915
            UnaryOperator::Y => "y".to_string(),
1✔
1916
            UnaryOperator::Z => "z".to_string(),
1✔
1917
        }
1918
    }
1919
}
1920

1921
/// Binary operator.
1922
///
1923
/// Operator applied between two operands, generally denoted "left" and "right".
1924
/// The type of the operands and the result are not necessarily the same. Valid
1925
/// operand types depend on the operator itself.
1926
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1927
pub enum BinaryOperator {
1928
    /// Addition operator.
1929
    ///
1930
    /// Returns the sum of its operands. Only valid for numeric operands.
1931
    Add,
1932

1933
    /// Inverse tangent operator with 2 arguments.
1934
    ///
1935
    /// Returns the arctangent (inverse tangent) of the ratio of the first
1936
    /// argument divided by the second argument.
1937
    Atan2,
1938

1939
    /// Cross product operator.
1940
    ///
1941
    /// Returns the cross product of the left and right operands. Only valid for
1942
    /// vector type operands of size 3. Always produce a vector result of the
1943
    /// same size.
1944
    Cross,
1945

1946
    /// Distance operator.
1947
    ///
1948
    /// Returns the distance between two floating point scalar or vectors, that
1949
    /// is `length(right - left)`.
1950
    Distance,
1951

1952
    /// Division operator.
1953
    ///
1954
    /// Returns the left operand divided by the right operand. Only valid for
1955
    /// numeric operands.
1956
    Div,
1957

1958
    /// Dot product operator.
1959
    ///
1960
    /// Returns the dot product of the left and right operands. Only valid for
1961
    /// vector type operands. Always produce a scalar floating-point result.
1962
    Dot,
1963

1964
    /// Greater-than operator.
1965
    ///
1966
    /// Returns `true` if the left operand is strictly greater than the right
1967
    /// operand. Only valid for numeric types. If the operands are vectors,
1968
    /// they must be of the same rank, and the result is a bool vector of
1969
    /// that rank.
1970
    GreaterThan,
1971

1972
    /// Greater-than-or-equal operator.
1973
    ///
1974
    /// Returns `true` if the left operand is greater than or equal to the right
1975
    /// operand. Only valid for numeric types. If the operands are vectors,
1976
    /// they must be of the same rank, and the result is a bool vector of
1977
    /// that rank.
1978
    GreaterThanOrEqual,
1979

1980
    /// Less-than operator.
1981
    ///
1982
    /// Returns `true` if the left operand is strictly less than the right
1983
    /// operand. Only valid for numeric types. If the operands are vectors,
1984
    /// they must be of the same rank, and the result is a bool vector of
1985
    /// that rank.
1986
    LessThan,
1987

1988
    /// Less-than-or-equal operator.
1989
    ///
1990
    /// Returns `true` if the left operand is less than or equal to the right
1991
    /// operand. Only valid for numeric types. If the operands are vectors,
1992
    /// they must be of the same rank, and the result is a bool vector of
1993
    /// that rank.
1994
    LessThanOrEqual,
1995

1996
    /// Maximum operator.
1997
    ///
1998
    /// Returns the maximum value of its left and right operands. Only valid for
1999
    /// numeric types. If the operands are vectors, they must be of the same
2000
    /// rank, and the result is a vector of that rank and same element
2001
    /// scalar type.
2002
    Max,
2003

2004
    /// Minimum operator.
2005
    ///
2006
    /// Returns the minimum value of its left and right operands. Only valid for
2007
    /// numeric types. If the operands are vectors, they must be of the same
2008
    /// rank, and the result is a vector of that rank and same element
2009
    /// scalar type.
2010
    Min,
2011

2012
    /// Multiply operator.
2013
    ///
2014
    /// Returns the product of its operands. Only valid for numeric operands.
2015
    Mul,
2016

2017
    /// Remainder operator.
2018
    ///
2019
    /// Returns the remainder of the division of the first operand by the
2020
    /// second. Only valid for numeric types. If the operands are vectors,
2021
    /// they must be of the same rank, and the result is a vector of that
2022
    /// rank and same element scalar type.
2023
    Remainder,
2024

2025
    /// Stepping operator.
2026
    ///
2027
    /// Returns `1.0` if the left operand is less than or equal to the right
2028
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
2029
    /// of the same rank, and applied component-wise for vectors.
2030
    Step,
2031

2032
    /// Subtraction operator.
2033
    ///
2034
    /// Returns the difference between its left and right operands. Only valid
2035
    /// for numeric operands.
2036
    Sub,
2037

2038
    /// Uniform random number operator.
2039
    ///
2040
    /// Returns a value generated by a fast non-cryptographically-secure
2041
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2042
    /// are undefined and generally focused around speed. The random value is
2043
    /// uniformly distributed between the left and right operands, which must be
2044
    /// numeric types. If the operands are vectors, they must be of the same
2045
    /// rank, and the result is a vector of that rank and same element
2046
    /// scalar type.
2047
    UniformRand,
2048

2049
    /// Normal distribution random number operator.
2050
    ///
2051
    /// Returns a value generated by a fast non-cryptographically-secure
2052
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2053
    /// are undefined and generally focused around speed. The random value is
2054
    /// normally distributed with mean given by the first operand and standard
2055
    /// deviation by the second, which must be numeric types. If the operands
2056
    /// are vectors, they must be of the same rank, and the result is a vector
2057
    /// of that rank and same element scalar type.
2058
    NormalRand,
2059

2060
    /// Constructor for 2-element vectors.
2061
    ///
2062
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
2063
    /// those two elements `(x, y)`.
2064
    Vec2,
2065

2066
    /// Constructor for a 4-element vector.
2067
    ///
2068
    /// Given a 3-element vector `xyz` and a scalar value `w`, returns the
2069
    /// vector `vec4(xyz, w)`.
2070
    Vec4XyzW,
2071
}
2072

2073
impl BinaryOperator {
2074
    /// Check if a binary operator is called via a functional-style call.
2075
    ///
2076
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
2077
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
2078
    /// like `a + b` for example. This check is used for formatting the WGSL
2079
    /// code emitted during evaluation of a binary operation expression.
2080
    pub fn is_functional(&self) -> bool {
39✔
2081
        match *self {
39✔
2082
            BinaryOperator::Add
2083
            | BinaryOperator::Div
2084
            | BinaryOperator::GreaterThan
2085
            | BinaryOperator::GreaterThanOrEqual
2086
            | BinaryOperator::LessThan
2087
            | BinaryOperator::LessThanOrEqual
2088
            | BinaryOperator::Mul
2089
            | BinaryOperator::Remainder
2090
            | BinaryOperator::Sub => false,
27✔
2091
            BinaryOperator::Atan2
2092
            | BinaryOperator::Cross
2093
            | BinaryOperator::Distance
2094
            | BinaryOperator::Dot
2095
            | BinaryOperator::Max
2096
            | BinaryOperator::Min
2097
            | BinaryOperator::Step
2098
            | BinaryOperator::UniformRand
2099
            | BinaryOperator::NormalRand
2100
            | BinaryOperator::Vec2
2101
            | BinaryOperator::Vec4XyzW => true,
12✔
2102
        }
2103
    }
2104

2105
    /// Check if a binary operator needs a type suffix.
2106
    ///
2107
    /// This is currently just for `rand_uniform`
2108
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2109
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2110
    /// WGSL doesn't support user-defined function overloading, so we need a
2111
    /// suffix to disambiguate the types.
2112
    pub fn needs_type_suffix(&self) -> bool {
12✔
2113
        matches!(
12✔
2114
            *self,
12✔
2115
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2116
        )
2117
    }
2118
}
2119

2120
impl ToWgslString for BinaryOperator {
2121
    fn to_wgsl_string(&self) -> String {
39✔
2122
        match *self {
39✔
2123
            BinaryOperator::Add => "+".to_string(),
5✔
2124
            BinaryOperator::Atan2 => "atan2".to_string(),
1✔
2125
            BinaryOperator::Cross => "cross".to_string(),
1✔
2126
            BinaryOperator::Distance => "distance".to_string(),
1✔
2127
            BinaryOperator::Div => "/".to_string(),
2✔
2128
            BinaryOperator::Dot => "dot".to_string(),
1✔
2129
            BinaryOperator::GreaterThan => ">".to_string(),
3✔
2130
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
1✔
2131
            BinaryOperator::LessThan => "<".to_string(),
1✔
2132
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
1✔
2133
            BinaryOperator::Max => "max".to_string(),
5✔
2134
            BinaryOperator::Min => "min".to_string(),
2✔
2135
            BinaryOperator::Mul => "*".to_string(),
6✔
2136
            BinaryOperator::Remainder => "%".to_string(),
1✔
2137
            BinaryOperator::Step => "step".to_string(),
1✔
2138
            BinaryOperator::Sub => "-".to_string(),
7✔
2139
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
2140
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
2141
            BinaryOperator::Vec2 => "vec2".to_string(),
×
NEW
2142
            BinaryOperator::Vec4XyzW => "vec4".to_string(),
×
2143
        }
2144
    }
2145
}
2146

2147
/// Ternary operator.
2148
///
2149
/// Operator applied between three operands. The type of the operands and the
2150
/// result are not necessarily the same. Valid operand types depend on the
2151
/// operator itself.
2152
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2153
pub enum TernaryOperator {
2154
    /// Linear blend ("mix") operator.
2155
    ///
2156
    /// Returns the linear blend between the first and second argument, based on
2157
    /// the fraction of the third argument. If the operands are vectors, they
2158
    /// must be of the same rank, and the result is a vector of that rank
2159
    /// and same element scalar type.
2160
    ///
2161
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2162
    /// (1 - t) + y * t`.
2163
    Mix,
2164

2165
    /// Smooth stepping operator.
2166
    ///
2167
    /// Returns the smooth Hermitian interpolation between the first and second
2168
    /// argument, calculated at the third argument. If the operands are vectors,
2169
    /// they must be of the same rank, and the result is a vector of that
2170
    /// rank and same element scalar type.
2171
    ///
2172
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2173
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2174
    /// represents the fractional position of `x` between `low` and `high`.
2175
    ///
2176
    /// The result is always a floating point scalar in \[0:1\].
2177
    SmoothStep,
2178

2179
    /// Constructor for 3-element vectors.
2180
    ///
2181
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2182
    /// consisting of those three elements `(x, y, z)`.
2183
    Vec3,
2184
}
2185

2186
impl ToWgslString for TernaryOperator {
2187
    fn to_wgsl_string(&self) -> String {
3✔
2188
        match *self {
3✔
2189
            TernaryOperator::Mix => "mix".to_string(),
2✔
2190
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
1✔
2191
            TernaryOperator::Vec3 => "vec3".to_string(),
×
2192
        }
2193
    }
2194
}
2195

2196
/// Expression writer.
2197
///
2198
/// Utility to write expressions with a simple functional syntax. Expressions
2199
/// created with the writer are gatherned into a [`Module`] which can be
2200
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2201
///
2202
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2203
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2204
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2205
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2206
/// to assign it to the [`EffectAsset`].
2207
///
2208
/// # Example
2209
///
2210
/// ```
2211
/// # use bevy_hanabi::*;
2212
/// # use bevy::prelude::*;
2213
/// // Create a writer
2214
/// let w = ExprWriter::new();
2215
///
2216
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2217
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2218
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2219
///
2220
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2221
/// let expr: ExprHandle = expr.expr();
2222
///
2223
/// // Create a modifier and assign the expression to one of its input(s)
2224
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2225
///
2226
/// // Create an EffectAsset with the modifier and the Module from the writer
2227
/// let effect = EffectAsset::new(1024, SpawnerSettings::rate(32_f32.into()), w.finish())
2228
///     .init(init_modifier);
2229
/// ```
2230
///
2231
/// [`finish()`]: ExprWriter::finish
2232
/// [`EffectAsset`]: crate::EffectAsset
2233
/// [`Modifer`]: crate::Modifier
2234
#[derive(Debug, Default, Clone)]
2235
pub struct ExprWriter {
2236
    module: Rc<RefCell<Module>>,
2237
}
2238

2239
#[allow(dead_code)]
2240
impl ExprWriter {
2241
    /// Create a new writer.
2242
    ///
2243
    /// The writer owns a new [`Module`] internally, and write all expressions
2244
    /// to it. The module can be released to the user with [`finish()`] once
2245
    /// done using the writer.
2246
    ///
2247
    /// [`finish()`]: ExprWriter::finish
2248
    pub fn new() -> Self {
3✔
2249
        Self {
2250
            module: Rc::new(RefCell::new(Module::default())),
3✔
2251
        }
2252
    }
2253

2254
    /// Create a new writer from an existing module.
2255
    ///
2256
    /// This is an advanced use entry point to write expressions into an
2257
    /// existing [`Module`]. In general, users should prefer using
2258
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2259
    /// same [`ExprWriter`] to write all expressions of the same
2260
    /// [`EffectAsset`].
2261
    ///
2262
    /// [`EffectAsset`]: crate::EffectAsset
2263
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2264
        Self { module }
2265
    }
2266

2267
    /// Add a new property.
2268
    ///
2269
    /// See [`Property`] for more details on what effect properties are.
2270
    ///
2271
    /// # Panics
2272
    ///
2273
    /// Panics if a property with the same name already exists.
2274
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2275
        self.module.borrow_mut().add_property(name, default_value)
1✔
2276
    }
2277

2278
    /// Push a new expression into the writer.
2279
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2280
        let expr = {
13✔
2281
            let mut m = self.module.borrow_mut();
13✔
2282
            m.push(expr.into())
13✔
2283
        };
2284
        WriterExpr {
2285
            expr,
2286
            module: Rc::clone(&self.module),
13✔
2287
        }
2288
    }
2289

2290
    /// Create a new writer expression from a literal constant.
2291
    ///
2292
    /// # Example
2293
    ///
2294
    /// ```
2295
    /// # use bevy_hanabi::*;
2296
    /// let mut w = ExprWriter::new();
2297
    /// let x = w.lit(-3.5); // x = -3.5;
2298
    /// ```
2299
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2300
        self.push(Expr::Literal(LiteralExpr {
11✔
2301
            value: value.into(),
11✔
2302
        }))
2303
    }
2304

2305
    /// Create a new writer expression from an attribute.
2306
    ///
2307
    /// # Example
2308
    ///
2309
    /// ```
2310
    /// # use bevy_hanabi::*;
2311
    /// let mut w = ExprWriter::new();
2312
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2313
    /// ```
2314
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2315
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
1✔
2316
    }
2317

2318
    /// Create a new writer expression from an attribute on a parent effect.
2319
    ///
2320
    /// # Example
2321
    ///
2322
    /// ```
2323
    /// # use bevy_hanabi::*;
2324
    /// let mut w = ExprWriter::new();
2325
    /// let x = w.parent_attr(Attribute::POSITION); // x = parent_particle.position;
2326
    /// ```
2327
    pub fn parent_attr(&self, attr: Attribute) -> WriterExpr {
×
2328
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
2329
    }
2330

2331
    /// Create a new writer expression from a property.
2332
    ///
2333
    /// # Example
2334
    ///
2335
    /// ```
2336
    /// # use bevy_hanabi::*;
2337
    /// let mut w = ExprWriter::new();
2338
    /// let prop = w.add_property("my_prop", 3.0.into());
2339
    /// let x = w.prop(prop); // x = properties.my_prop;
2340
    /// ```
2341
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2342
        self.push(Expr::Property(PropertyExpr::new(handle)))
1✔
2343
    }
2344

2345
    /// Create a new writer expression representing the current simulation time.
2346
    ///
2347
    /// # Example
2348
    ///
2349
    /// ```
2350
    /// # use bevy_hanabi::*;
2351
    /// let mut w = ExprWriter::new();
2352
    /// let x = w.time(); // x = sim_params.time;
2353
    /// ```
2354
    pub fn time(&self) -> WriterExpr {
×
2355
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2356
    }
2357

2358
    /// Create a new writer expression representing the simulation delta time
2359
    /// since last frame.
2360
    ///
2361
    /// # Example
2362
    ///
2363
    /// ```
2364
    /// # use bevy_hanabi::*;
2365
    /// let mut w = ExprWriter::new();
2366
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2367
    /// ```
2368
    pub fn delta_time(&self) -> WriterExpr {
×
2369
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2370
    }
2371

2372
    /// Create a new writer expression representing a random value of the given
2373
    /// type.
2374
    ///
2375
    /// The type can be any scalar or vector type. Matrix types are not
2376
    /// supported. The random values generated are uniformly distributed in
2377
    /// `[0:1]`. For vectors, each component is sampled separately.
2378
    ///
2379
    /// # Panics
2380
    ///
2381
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2382
    ///
2383
    /// # Example
2384
    ///
2385
    /// ```
2386
    /// # use bevy_hanabi::*;
2387
    /// let mut w = ExprWriter::new();
2388
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2389
    /// ```
2390
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2391
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2392
            value_type.into(),
×
2393
        ))))
2394
    }
2395

2396
    /// Create a new writer expression representing the alpha cutoff value used
2397
    /// for alpha masking.
2398
    ///
2399
    /// This expression is only valid when used in the context of the fragment
2400
    /// shader, in the render context.
2401
    ///
2402
    /// # Example
2403
    ///
2404
    /// ```
2405
    /// # use bevy_hanabi::*;
2406
    /// let mut w = ExprWriter::new();
2407
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2408
    /// ```
2409
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2410
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2411
            BuiltInOperator::AlphaCutoff,
×
2412
        )))
2413
    }
2414

2415
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2416
    /// were written by the writer.
2417
    ///
2418
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2419
    /// to that effect the modifiers which use the expressions created by this
2420
    /// writer.
2421
    ///
2422
    /// # Example
2423
    ///
2424
    /// ```
2425
    /// # use bevy_hanabi::*;
2426
    /// # let spawner = SpawnerSettings::default();
2427
    /// let mut w = ExprWriter::new();
2428
    /// // [...]
2429
    /// let module = w.finish();
2430
    /// let asset = EffectAsset::new(256, spawner, module);
2431
    /// ```
2432
    ///
2433
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2434
    pub fn finish(self) -> Module {
3✔
2435
        self.module.take()
3✔
2436
    }
2437
}
2438

2439
/// Intermediate expression from an [`ExprWriter`].
2440
///
2441
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2442
/// retains a reference to the underlying [`Module`] and therefore can easily be
2443
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2444
/// being more heavyweight and locking the underlying [`Module`] under a
2445
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2446
/// opposition is a very lightweight type, similar to a simple index. And like
2447
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2448
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2449
///
2450
/// In addition, [`WriterExpr`] implements several numerical operators like the
2451
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2452
/// [`WriterExpr`].
2453
///
2454
/// ```
2455
/// # use bevy_hanabi::*;
2456
/// let mut w = ExprWriter::new();
2457
/// let x = w.lit(-3.5);
2458
/// let y = w.lit(78.);
2459
/// let z = x + y; // == 74.5
2460
/// ```
2461
///
2462
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2463
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2464
///
2465
/// ```
2466
/// # use bevy_hanabi::*;
2467
/// let mut w = ExprWriter::new();
2468
/// let my_prop = w.add_property("my_prop", 3.0.into());
2469
///
2470
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2471
/// let x = (w.lit(-3.5) + w.lit(1.))
2472
///     .max(w.prop(my_prop))
2473
///     .mul(w.lit(0.5))
2474
///     .sub(w.attr(Attribute::POSITION));
2475
///
2476
/// let handle: ExprHandle = x.expr();
2477
/// ```
2478
#[derive(Debug, Clone)]
2479
pub struct WriterExpr {
2480
    expr: ExprHandle,
2481
    module: Rc<RefCell<Module>>,
2482
}
2483

2484
impl WriterExpr {
2485
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2486
        let expr = self.module.borrow_mut().push(Expr::Unary {
1✔
2487
            op,
1✔
2488
            expr: self.expr,
1✔
2489
        });
2490
        WriterExpr {
2491
            expr,
2492
            module: self.module,
1✔
2493
        }
2494
    }
2495

2496
    /// Take the absolute value of the current expression.
2497
    ///
2498
    /// This is a unary operator, which applies component-wise to vector and
2499
    /// matrix operand expressions.
2500
    ///
2501
    /// # Example
2502
    ///
2503
    /// ```
2504
    /// # use bevy_hanabi::*;
2505
    /// # let mut w = ExprWriter::new();
2506
    /// // A literal expression `x = -3.5;`.
2507
    /// let x = w.lit(-3.5);
2508
    ///
2509
    /// // The absolute value `y = abs(x);`.
2510
    /// let y = x.abs(); // == 3.5
2511
    /// ```
2512
    #[inline]
2513
    pub fn abs(self) -> Self {
1✔
2514
        self.unary_op(UnaryOperator::Abs)
1✔
2515
    }
2516

2517
    /// Apply the logical operator "all" to the current bool vector expression.
2518
    ///
2519
    /// This is a unary operator, which applies to vector operand expressions to
2520
    /// produce a scalar boolean.
2521
    ///
2522
    /// # Example
2523
    ///
2524
    /// ```
2525
    /// # use bevy_hanabi::*;
2526
    /// # use bevy::math::BVec3;
2527
    /// # let mut w = ExprWriter::new();
2528
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2529
    /// let x = w.lit(BVec3::new(true, false, true));
2530
    ///
2531
    /// // Check if all components are true `y = all(x);`.
2532
    /// let y = x.all(); // == false
2533
    /// ```
2534
    #[inline]
2535
    pub fn all(self) -> Self {
×
2536
        self.unary_op(UnaryOperator::All)
×
2537
    }
2538

2539
    /// Apply the logical operator "any" to the current bool vector expression.
2540
    ///
2541
    /// This is a unary operator, which applies to vector operand expressions to
2542
    /// produce a scalar boolean.
2543
    ///
2544
    /// # Example
2545
    ///
2546
    /// ```
2547
    /// # use bevy_hanabi::*;
2548
    /// # use bevy::math::BVec3;
2549
    /// # let mut w = ExprWriter::new();
2550
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2551
    /// let x = w.lit(BVec3::new(true, false, true));
2552
    ///
2553
    /// // Check if any components is true `y = any(x);`.
2554
    /// let y = x.any(); // == true
2555
    /// ```
2556
    #[inline]
2557
    pub fn any(self) -> Self {
×
2558
        self.unary_op(UnaryOperator::Any)
×
2559
    }
2560

2561
    /// Apply the "acos" (inverse cosine) operator to the current float scalar
2562
    /// or vector expression.
2563
    ///
2564
    /// This is a unary operator, which applies to float scalar or vector
2565
    /// operand expressions to produce a float scalar or vector. It applies
2566
    /// component-wise to vector operand expressions. The return value lies in
2567
    /// the 0 ≤ x ≤ π range.
2568
    ///
2569
    /// # Example
2570
    ///
2571
    /// ```
2572
    /// # use bevy_hanabi::*;
2573
    /// # use bevy::math::Vec3;
2574
    /// # let mut w = ExprWriter::new();
2575
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2576
    /// let x = w.lit(Vec3::ONE);
2577
    ///
2578
    /// // Acos: `y = acos(x);`
2579
    /// let y = x.acos();
2580
    /// ```
2581
    #[inline]
2582
    pub fn acos(self) -> Self {
×
2583
        self.unary_op(UnaryOperator::Acos)
×
2584
    }
2585

2586
    /// Apply the "asin" (inverse sine) operator to the current float scalar or
2587
    /// vector expression.
2588
    ///
2589
    /// This is a unary operator, which applies to float scalar or vector
2590
    /// operand expressions to produce a float scalar or vector. It applies
2591
    /// component-wise to vector operand expressions. The return value lies in
2592
    /// the -π/2 ≤ x ≤ π/2 range.
2593
    ///
2594
    /// # Example
2595
    ///
2596
    /// ```
2597
    /// # use bevy_hanabi::*;
2598
    /// # use bevy::math::Vec3;
2599
    /// # let mut w = ExprWriter::new();
2600
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2601
    /// let x = w.lit(Vec3::ONE);
2602
    ///
2603
    /// // Asin: `y = asin(x);`
2604
    /// let y = x.asin();
2605
    /// ```
2606
    #[inline]
2607
    pub fn asin(self) -> Self {
×
2608
        self.unary_op(UnaryOperator::Asin)
×
2609
    }
2610

2611
    /// Apply the "atan" (inverse tangent) operator to the current float scalar
2612
    /// or vector expression.
2613
    ///
2614
    /// This is a unary operator, which applies to float scalar or vector
2615
    /// operand expressions to produce a float scalar or vector. It applies
2616
    /// component-wise to vector operand expressions. The return value lies in
2617
    /// the -π/2 ≤ x ≤ π/2 range.
2618
    ///
2619
    /// # Example
2620
    ///
2621
    /// ```
2622
    /// # use bevy_hanabi::*;
2623
    /// # use bevy::math::Vec3;
2624
    /// # let mut w = ExprWriter::new();
2625
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2626
    /// let x = w.lit(Vec3::ONE);
2627
    ///
2628
    /// // Atan: `y = atan(x);`
2629
    /// let y = x.atan();
2630
    /// ```
2631
    #[inline]
2632
    pub fn atan(self) -> Self {
×
2633
        self.unary_op(UnaryOperator::Atan)
×
2634
    }
2635

2636
    /// Apply the "ceil" operator to the current float scalar or vector
2637
    /// expression.
2638
    ///
2639
    /// This is a unary operator, which applies to float scalar or vector
2640
    /// operand expressions to produce a float scalar or vector. It applies
2641
    /// component-wise to vector operand expressions.
2642
    ///
2643
    /// # Example
2644
    ///
2645
    /// ```
2646
    /// # use bevy_hanabi::*;
2647
    /// # use bevy::math::Vec3;
2648
    /// # let mut w = ExprWriter::new();
2649
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2650
    /// let x = w.lit(Vec3::ONE);
2651
    ///
2652
    /// // Ceil: `y = ceil(x);`
2653
    /// let y = x.ceil();
2654
    /// ```
2655
    #[inline]
2656
    pub fn ceil(self) -> Self {
×
2657
        self.unary_op(UnaryOperator::Ceil)
×
2658
    }
2659

2660
    /// Apply the "cos" operator to the current float scalar or vector
2661
    /// expression.
2662
    ///
2663
    /// This is a unary operator, which applies to float scalar or vector
2664
    /// operand expressions to produce a float scalar or vector. It applies
2665
    /// component-wise to vector operand expressions.
2666
    ///
2667
    /// # Example
2668
    ///
2669
    /// ```
2670
    /// # use bevy_hanabi::*;
2671
    /// # use bevy::math::Vec3;
2672
    /// # let mut w = ExprWriter::new();
2673
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2674
    /// let x = w.lit(Vec3::ONE);
2675
    ///
2676
    /// // Cos: `y = cos(x);`
2677
    /// let y = x.cos();
2678
    /// ```
2679
    #[inline]
2680
    pub fn cos(self) -> Self {
×
2681
        self.unary_op(UnaryOperator::Cos)
×
2682
    }
2683

2684
    /// Apply the "exp" operator to the current float scalar or vector
2685
    /// expression.
2686
    ///
2687
    /// This is a unary operator, which applies to float scalar or vector
2688
    /// operand expressions to produce a float scalar or vector. It applies
2689
    /// component-wise to vector operand expressions.
2690
    ///
2691
    /// # Example
2692
    ///
2693
    /// ```
2694
    /// # use bevy_hanabi::*;
2695
    /// # use bevy::math::Vec3;
2696
    /// # let mut w = ExprWriter::new();
2697
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2698
    /// let x = w.lit(Vec3::ONE);
2699
    ///
2700
    /// // Exp: `y = exp(x);`
2701
    /// let y = x.exp();
2702
    /// ```
2703
    #[inline]
2704
    pub fn exp(self) -> Self {
×
2705
        self.unary_op(UnaryOperator::Exp)
×
2706
    }
2707

2708
    /// Apply the "exp2" operator to the current float scalar or vector
2709
    /// expression.
2710
    ///
2711
    /// This is a unary operator, which applies to float scalar or vector
2712
    /// operand expressions to produce a float scalar or vector. It applies
2713
    /// component-wise to vector operand expressions.
2714
    ///
2715
    /// # Example
2716
    ///
2717
    /// ```
2718
    /// # use bevy_hanabi::*;
2719
    /// # use bevy::math::Vec3;
2720
    /// # let mut w = ExprWriter::new();
2721
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2722
    /// let x = w.lit(Vec3::ONE);
2723
    ///
2724
    /// // Exp2: `y = exp2(x);`
2725
    /// let y = x.exp2();
2726
    /// ```
2727
    #[inline]
2728
    pub fn exp2(self) -> Self {
×
2729
        self.unary_op(UnaryOperator::Exp2)
×
2730
    }
2731

2732
    /// Apply the "floor" operator to the current float scalar or vector
2733
    /// expression.
2734
    ///
2735
    /// This is a unary operator, which applies to float scalar or vector
2736
    /// operand expressions to produce a float scalar or vector. It applies
2737
    /// component-wise to vector operand expressions.
2738
    ///
2739
    /// # Example
2740
    ///
2741
    /// ```
2742
    /// # use bevy_hanabi::*;
2743
    /// # use bevy::math::Vec3;
2744
    /// # let mut w = ExprWriter::new();
2745
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2746
    /// let x = w.lit(Vec3::ONE);
2747
    ///
2748
    /// // Floor: `y = floor(x);`
2749
    /// let y = x.floor();
2750
    /// ```
2751
    #[inline]
2752
    pub fn floor(self) -> Self {
×
2753
        self.unary_op(UnaryOperator::Floor)
×
2754
    }
2755

2756
    /// Apply the "fract" operator to the current float scalar or vector
2757
    /// expression.
2758
    ///
2759
    /// This is a unary operator, which applies to float scalar or vector
2760
    /// operand expressions to produce a float scalar or vector. It applies
2761
    /// component-wise to vector operand expressions.
2762
    ///
2763
    /// # Example
2764
    ///
2765
    /// ```
2766
    /// # use bevy_hanabi::*;
2767
    /// # use bevy::math::Vec3;
2768
    /// # let mut w = ExprWriter::new();
2769
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2770
    /// let x = w.lit(Vec3::ONE);
2771
    ///
2772
    /// // Fract: `y = fract(x);`
2773
    /// let y = x.fract();
2774
    /// ```
2775
    #[inline]
2776
    pub fn fract(self) -> Self {
×
2777
        self.unary_op(UnaryOperator::Fract)
×
2778
    }
2779

2780
    /// Apply the "inverseSqrt" (inverse square root) operator to the current
2781
    /// float scalar or vector expression.
2782
    ///
2783
    /// This is a unary operator, which applies to float scalar or vector
2784
    /// operand expressions to produce a float scalar or vector. It applies
2785
    /// component-wise to vector operand expressions.
2786
    ///
2787
    /// # Example
2788
    ///
2789
    /// ```
2790
    /// # use bevy_hanabi::*;
2791
    /// # use bevy::math::Vec3;
2792
    /// # let mut w = ExprWriter::new();
2793
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2794
    /// let x = w.lit(Vec3::ONE);
2795
    ///
2796
    /// // Inverse square root: `y = inverseSqrt(x) = 1.0 / sqrt(x);`
2797
    /// let y = x.inverse_sqrt();
2798
    /// ```
2799
    #[inline]
2800
    pub fn inverse_sqrt(self) -> Self {
×
2801
        self.unary_op(UnaryOperator::InvSqrt)
×
2802
    }
2803

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

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

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

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

2899
    /// Apply the "pack4x8snorm" operator to the current 4-component float
2900
    /// vector expression.
2901
    ///
2902
    /// This is a unary operator, which applies to 4-component float vector
2903
    /// operand expressions to produce a single `u32` scalar expression.
2904
    ///
2905
    /// # Example
2906
    ///
2907
    /// ```
2908
    /// # use bevy_hanabi::*;
2909
    /// # use bevy::math::Vec4;
2910
    /// # let mut w = ExprWriter::new();
2911
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2912
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2913
    ///
2914
    /// // Pack: `y = pack4x8snorm(x);`
2915
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
2916
    /// ```
2917
    #[inline]
2918
    pub fn pack4x8snorm(self) -> Self {
×
2919
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
2920
    }
2921

2922
    /// Apply the "pack4x8unorm" operator to the current 4-component float
2923
    /// vector expression.
2924
    ///
2925
    /// This is a unary operator, which applies to 4-component float vector
2926
    /// operand expressions to produce a single `u32` scalar expression.
2927
    ///
2928
    /// # Example
2929
    ///
2930
    /// ```
2931
    /// # use bevy_hanabi::*;
2932
    /// # use bevy::math::Vec4;
2933
    /// # let mut w = ExprWriter::new();
2934
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2935
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2936
    ///
2937
    /// // Pack: `y = pack4x8unorm(x);`
2938
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
2939
    /// ```
2940
    #[inline]
2941
    pub fn pack4x8unorm(self) -> Self {
×
2942
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
2943
    }
2944

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

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

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

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

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

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

3089
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
3090
    /// expression.
3091
    ///
3092
    /// This is a unary operator, which applies to `u32` scalar operand
3093
    /// expressions to produce a 4-component floating point vector of unsigned
3094
    /// normalized components in `[0:1]`.
3095
    ///
3096
    /// # Example
3097
    ///
3098
    /// ```
3099
    /// # use bevy_hanabi::*;
3100
    /// # use bevy::math::Vec3;
3101
    /// # let mut w = ExprWriter::new();
3102
    /// // A literal expression `y = 0xFF00FF00u32;`.
3103
    /// let y = w.lit(0xFF00FF00u32);
3104
    ///
3105
    /// // Unpack: `x = unpack4x8unorm(y);`
3106
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
3107
    /// ```
3108
    #[inline]
3109
    pub fn unpack4x8unorm(self) -> Self {
×
3110
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
3111
    }
3112

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

3137
    /// Get the first component of a scalar or vector.
3138
    ///
3139
    /// # Example
3140
    ///
3141
    /// ```
3142
    /// # use bevy_hanabi::*;
3143
    /// # use bevy::math::Vec3;
3144
    /// # let mut w = ExprWriter::new();
3145
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3146
    /// let v = w.lit(Vec3::ONE);
3147
    ///
3148
    /// // f = v.x;`
3149
    /// let f = v.x();
3150
    /// ```
3151
    #[inline]
3152
    pub fn x(self) -> Self {
×
3153
        self.unary_op(UnaryOperator::X)
×
3154
    }
3155

3156
    /// Get the second component of a vector.
3157
    ///
3158
    /// # Example
3159
    ///
3160
    /// ```
3161
    /// # use bevy_hanabi::*;
3162
    /// # use bevy::math::Vec3;
3163
    /// # let mut w = ExprWriter::new();
3164
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3165
    /// let v = w.lit(Vec3::ONE);
3166
    ///
3167
    /// // f = v.y;`
3168
    /// let f = v.y();
3169
    /// ```
3170
    #[inline]
3171
    pub fn y(self) -> Self {
×
3172
        self.unary_op(UnaryOperator::Y)
×
3173
    }
3174

3175
    /// Get the third component of a vector.
3176
    ///
3177
    /// # Example
3178
    ///
3179
    /// ```
3180
    /// # use bevy_hanabi::*;
3181
    /// # use bevy::math::Vec3;
3182
    /// # let mut w = ExprWriter::new();
3183
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3184
    /// let v = w.lit(Vec3::ONE);
3185
    ///
3186
    /// // f = v.z;`
3187
    /// let f = v.z();
3188
    /// ```
3189
    #[inline]
3190
    pub fn z(self) -> Self {
×
3191
        self.unary_op(UnaryOperator::Z)
×
3192
    }
3193

3194
    /// Get the fourth component of a vector.
3195
    ///
3196
    /// # Example
3197
    ///
3198
    /// ```
3199
    /// # use bevy_hanabi::*;
3200
    /// # use bevy::math::Vec3;
3201
    /// # let mut w = ExprWriter::new();
3202
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3203
    /// let v = w.lit(Vec3::ONE);
3204
    ///
3205
    /// // f = v.w;`
3206
    /// let f = v.w();
3207
    /// ```
3208
    #[inline]
3209
    pub fn w(self) -> Self {
×
3210
        self.unary_op(UnaryOperator::W)
×
3211
    }
3212

3213
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
3214
        assert_eq!(self.module, other.module);
5✔
3215
        let left = self.expr;
5✔
3216
        let right = other.expr;
5✔
3217
        let expr = self
5✔
3218
            .module
5✔
3219
            .borrow_mut()
3220
            .push(Expr::Binary { op, left, right });
5✔
3221
        WriterExpr {
3222
            expr,
3223
            module: self.module,
5✔
3224
        }
3225
    }
3226

3227
    /// Add the current expression with another expression.
3228
    ///
3229
    /// This is a binary operator, which applies component-wise to vector
3230
    /// operand expressions.
3231
    ///
3232
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3233
    /// symbol, as an alternative to calling this method directly.
3234
    ///
3235
    /// # Example
3236
    ///
3237
    /// ```
3238
    /// # use bevy_hanabi::*;
3239
    /// # use bevy::math::Vec2;
3240
    /// # let mut w = ExprWriter::new();
3241
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3242
    /// let x = w.lit(Vec2::new(3., -2.));
3243
    ///
3244
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3245
    /// let y = w.lit(Vec2::new(1., 5.));
3246
    ///
3247
    /// // The sum of both vectors `z = x + y;`.
3248
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3249
    ///                   // -OR-
3250
    ///                   // let z = x + y;
3251
    /// ```
3252
    #[allow(clippy::should_implement_trait)]
3253
    #[inline]
3254
    pub fn add(self, other: Self) -> Self {
2✔
3255
        self.binary_op(other, BinaryOperator::Add)
2✔
3256
    }
3257

3258
    /// Apply the "atan2" (inverse tangent with 2 arguments) operator to the
3259
    /// current float scalar or vector expression.
3260
    ///
3261
    /// This is a unary operator, which applies to float scalar or vector
3262
    /// operand expressions to produce a float scalar or vector. It applies
3263
    /// component-wise to vector operand expressions. The return value lies in
3264
    /// the -π ≤ x ≤ π range, and represents a value whose tangent is equal to
3265
    /// y over x (`z = atan2(y, x)` <=> `tan(z) = y / x`).
3266
    ///
3267
    /// # Example
3268
    ///
3269
    /// ```
3270
    /// # use bevy_hanabi::*;
3271
    /// # use bevy::math::Vec3;
3272
    /// # let mut w = ExprWriter::new();
3273
    /// // Two literal expressions `x` and `y`.
3274
    /// let x = w.lit(Vec3::new(1., 0., -1.));
3275
    /// let y = w.lit(Vec3::ONE);
3276
    ///
3277
    /// // Atan: `z = atan2(y, x);`
3278
    /// let z = y.atan2(x);
3279
    /// ```
3280
    #[inline]
3281
    pub fn atan2(self, other: Self) -> Self {
×
3282
        self.binary_op(other, BinaryOperator::Atan2)
×
3283
    }
3284

3285
    /// Calculate the cross product of the current expression by another
3286
    /// expression.
3287
    ///
3288
    /// This is a binary operator, which applies to vector operands of size 3
3289
    /// only, and always produces a vector of the same size.
3290
    ///
3291
    /// # Example
3292
    ///
3293
    /// ```
3294
    /// # use bevy_hanabi::*;
3295
    /// # use bevy::math::Vec3;
3296
    /// # let mut w = ExprWriter::new();
3297
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3298
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3299
    ///
3300
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3301
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3302
    ///
3303
    /// // The cross product of both vectors `z = cross(x, y);`.
3304
    /// let z = x.cross(y);
3305
    /// ```
3306
    #[inline]
3307
    pub fn cross(self, other: Self) -> Self {
×
3308
        self.binary_op(other, BinaryOperator::Cross)
×
3309
    }
3310

3311
    /// Calculate the dot product of the current expression by another
3312
    /// expression.
3313
    ///
3314
    /// This is a binary operator, which applies to vector operands of same size
3315
    /// only, and always produces a floating point scalar.
3316
    ///
3317
    /// # Example
3318
    ///
3319
    /// ```
3320
    /// # use bevy_hanabi::*;
3321
    /// # use bevy::math::Vec2;
3322
    /// # let mut w = ExprWriter::new();
3323
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3324
    /// let x = w.lit(Vec2::new(3., -2.));
3325
    ///
3326
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3327
    /// let y = w.lit(Vec2::new(1., 5.));
3328
    ///
3329
    /// // The dot product of both vectors `z = dot(x, y);`.
3330
    /// let z = x.dot(y);
3331
    /// ```
3332
    #[inline]
3333
    pub fn dot(self, other: Self) -> Self {
×
3334
        self.binary_op(other, BinaryOperator::Dot)
×
3335
    }
3336

3337
    /// Calculate the distance between the current expression and another
3338
    /// expression.
3339
    ///
3340
    /// This is a binary operator.
3341
    ///
3342
    /// # Example
3343
    ///
3344
    /// ```
3345
    /// # use bevy_hanabi::*;
3346
    /// # use bevy::math::Vec3;
3347
    /// # let mut w = ExprWriter::new();
3348
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3349
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3350
    ///
3351
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3352
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3353
    ///
3354
    /// // The distance between the vectors `z = distance(x, y);`.
3355
    /// let z = x.distance(y);
3356
    /// ```
3357
    #[inline]
3358
    pub fn distance(self, other: Self) -> Self {
×
3359
        self.binary_op(other, BinaryOperator::Distance)
×
3360
    }
3361

3362
    /// Divide the current expression by another expression.
3363
    ///
3364
    /// This is a binary operator, which applies component-wise to vector
3365
    /// operand expressions.
3366
    ///
3367
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3368
    /// symbol, as an alternative to calling this method directly.
3369
    ///
3370
    /// # Example
3371
    ///
3372
    /// ```
3373
    /// # use bevy_hanabi::*;
3374
    /// # use bevy::math::Vec2;
3375
    /// # let mut w = ExprWriter::new();
3376
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3377
    /// let x = w.lit(Vec2::new(3., -2.));
3378
    ///
3379
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3380
    /// let y = w.lit(Vec2::new(1., 5.));
3381
    ///
3382
    /// // The quotient of both vectors `z = x / y;`.
3383
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3384
    ///                   // -OR-
3385
    ///                   // let z = x / y;
3386
    /// ```
3387
    #[allow(clippy::should_implement_trait)]
3388
    #[inline]
3389
    pub fn div(self, other: Self) -> Self {
×
3390
        self.binary_op(other, BinaryOperator::Div)
×
3391
    }
3392

3393
    /// Apply the logical operator "greater than or equal" to this expression
3394
    /// and another expression.
3395
    ///
3396
    /// This is a binary operator, which applies component-wise to vector
3397
    /// operand expressions.
3398
    ///
3399
    /// # Example
3400
    ///
3401
    /// ```
3402
    /// # use bevy_hanabi::*;
3403
    /// # use bevy::math::Vec3;
3404
    /// # let mut w = ExprWriter::new();
3405
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3406
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3407
    ///
3408
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3409
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3410
    ///
3411
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3412
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3413
    /// ```
3414
    #[inline]
3415
    pub fn ge(self, other: Self) -> Self {
×
3416
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3417
    }
3418

3419
    /// Apply the logical operator "greater than" to this expression and another
3420
    /// expression.
3421
    ///
3422
    /// This is a binary operator, which applies component-wise to vector
3423
    /// operand expressions.
3424
    ///
3425
    /// # Example
3426
    ///
3427
    /// ```
3428
    /// # use bevy_hanabi::*;
3429
    /// # use bevy::math::Vec3;
3430
    /// # let mut w = ExprWriter::new();
3431
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3432
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3433
    ///
3434
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3435
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3436
    ///
3437
    /// // The boolean result of the greater than operation `z = (x > y);`.
3438
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3439
    /// ```
3440
    #[inline]
3441
    pub fn gt(self, other: Self) -> Self {
×
3442
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3443
    }
3444

3445
    /// Apply the logical operator "less than or equal" to this expression and
3446
    /// another expression.
3447
    ///
3448
    /// This is a binary operator, which applies component-wise to vector
3449
    /// operand expressions.
3450
    ///
3451
    /// # Example
3452
    ///
3453
    /// ```
3454
    /// # use bevy_hanabi::*;
3455
    /// # use bevy::math::Vec3;
3456
    /// # let mut w = ExprWriter::new();
3457
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3458
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3459
    ///
3460
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3461
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3462
    ///
3463
    /// // The boolean result of the less than or equal operation `z = (x <= y);`.
3464
    /// let z = x.le(y); // == vec3<bool>(false, true, true)
3465
    /// ```
3466
    #[inline]
3467
    pub fn le(self, other: Self) -> Self {
×
3468
        self.binary_op(other, BinaryOperator::LessThanOrEqual)
×
3469
    }
3470

3471
    /// Apply the logical operator "less than" to this expression and another
3472
    /// expression.
3473
    ///
3474
    /// This is a binary operator, which applies component-wise to vector
3475
    /// operand expressions.
3476
    ///
3477
    /// # Example
3478
    ///
3479
    /// ```
3480
    /// # use bevy_hanabi::*;
3481
    /// # use bevy::math::Vec3;
3482
    /// # let mut w = ExprWriter::new();
3483
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3484
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3485
    ///
3486
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3487
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3488
    ///
3489
    /// // The boolean result of the less than operation `z = (x < y);`.
3490
    /// let z = x.lt(y); // == vec3<bool>(false, true, false)
3491
    /// ```
3492
    #[inline]
3493
    pub fn lt(self, other: Self) -> Self {
×
3494
        self.binary_op(other, BinaryOperator::LessThan)
×
3495
    }
3496

3497
    /// Take the maximum value of the current expression and another expression.
3498
    ///
3499
    /// This is a binary operator, which applies component-wise to vector
3500
    /// operand expressions.
3501
    ///
3502
    /// # Example
3503
    ///
3504
    /// ```
3505
    /// # use bevy_hanabi::*;
3506
    /// # use bevy::math::Vec2;
3507
    /// # let mut w = ExprWriter::new();
3508
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3509
    /// let x = w.lit(Vec2::new(3., -2.));
3510
    ///
3511
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3512
    /// let y = w.lit(Vec2::new(1., 5.));
3513
    ///
3514
    /// // The maximum of both vectors `z = max(x, y);`.
3515
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3516
    /// ```
3517
    #[inline]
3518
    pub fn max(self, other: Self) -> Self {
1✔
3519
        self.binary_op(other, BinaryOperator::Max)
1✔
3520
    }
3521

3522
    /// Take the minimum value of the current expression and another expression.
3523
    ///
3524
    /// This is a binary operator, which applies component-wise to vector
3525
    /// operand expressions.
3526
    ///
3527
    /// # Example
3528
    ///
3529
    /// ```
3530
    /// # use bevy_hanabi::*;
3531
    /// # use bevy::math::Vec2;
3532
    /// # let mut w = ExprWriter::new();
3533
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3534
    /// let x = w.lit(Vec2::new(3., -2.));
3535
    ///
3536
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3537
    /// let y = w.lit(Vec2::new(1., 5.));
3538
    ///
3539
    /// // The minimum of both vectors `z = min(x, y);`.
3540
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3541
    /// ```
3542
    #[inline]
3543
    pub fn min(self, other: Self) -> Self {
1✔
3544
        self.binary_op(other, BinaryOperator::Min)
1✔
3545
    }
3546

3547
    /// Multiply the current expression with another expression.
3548
    ///
3549
    /// This is a binary operator, which applies component-wise to vector
3550
    /// operand expressions.
3551
    ///
3552
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3553
    /// symbol, as an alternative to calling this method directly.
3554
    ///
3555
    /// # Example
3556
    ///
3557
    /// ```
3558
    /// # use bevy_hanabi::*;
3559
    /// # use bevy::math::Vec2;
3560
    /// # let mut w = ExprWriter::new();
3561
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3562
    /// let x = w.lit(Vec2::new(3., -2.));
3563
    ///
3564
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3565
    /// let y = w.lit(Vec2::new(1., 5.));
3566
    ///
3567
    /// // The product of both vectors `z = x * y;`.
3568
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3569
    ///                   // -OR-
3570
    ///                   // let z = x * y;
3571
    /// ```
3572
    #[allow(clippy::should_implement_trait)]
3573
    #[inline]
3574
    pub fn mul(self, other: Self) -> Self {
1✔
3575
        self.binary_op(other, BinaryOperator::Mul)
1✔
3576
    }
3577

3578
    /// Calculate the remainder of the division of the current expression by
3579
    /// another expression.
3580
    ///
3581
    /// This is a binary operator.
3582
    ///
3583
    /// # Example
3584
    ///
3585
    /// ```
3586
    /// # use bevy_hanabi::*;
3587
    /// # use bevy::math::Vec3;
3588
    /// # let mut w = ExprWriter::new();
3589
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3590
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3591
    ///
3592
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3593
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3594
    ///
3595
    /// // The remainder of the division `z = x % y;`.
3596
    /// let z = x.rem(y);
3597
    /// ```
3598
    #[allow(clippy::should_implement_trait)]
3599
    #[inline]
3600
    pub fn rem(self, other: Self) -> Self {
×
3601
        self.binary_op(other, BinaryOperator::Remainder)
×
3602
    }
3603

3604
    /// Calculate the step of a value with respect to a reference.
3605
    ///
3606
    /// This is a binary operator, which applies component-wise to vector
3607
    /// operand expressions.
3608
    ///
3609
    /// # Example
3610
    ///
3611
    /// ```
3612
    /// # use bevy_hanabi::*;
3613
    /// # use bevy::math::Vec3;
3614
    /// # let mut w = ExprWriter::new();
3615
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3616
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3617
    ///
3618
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3619
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3620
    ///
3621
    /// // The step value
3622
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3623
    /// ```
3624
    #[allow(clippy::should_implement_trait)]
3625
    #[inline]
3626
    pub fn step(self, edge: Self) -> Self {
×
3627
        // Note: order is step(edge, x) but x.step(edge)
3628
        edge.binary_op(self, BinaryOperator::Step)
×
3629
    }
3630

3631
    /// Subtract another expression from the current expression.
3632
    ///
3633
    /// This is a binary operator, which applies component-wise to vector
3634
    /// operand expressions.
3635
    ///
3636
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3637
    /// symbol, as an alternative to calling this method directly.
3638
    ///
3639
    /// # Example
3640
    ///
3641
    /// ```
3642
    /// # use bevy_hanabi::*;
3643
    /// # use bevy::math::Vec2;
3644
    /// # let mut w = ExprWriter::new();
3645
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3646
    /// let x = w.lit(Vec2::new(3., -2.));
3647
    ///
3648
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3649
    /// let y = w.lit(Vec2::new(1., 5.));
3650
    ///
3651
    /// // The difference of both vectors `z = x - y;`.
3652
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3653
    ///                   // -OR-
3654
    ///                   // let z = x - y;
3655
    /// ```
3656
    #[allow(clippy::should_implement_trait)]
3657
    #[inline]
3658
    pub fn sub(self, other: Self) -> Self {
×
3659
        self.binary_op(other, BinaryOperator::Sub)
×
3660
    }
3661

3662
    /// Apply the logical operator "uniform" to this expression and another
3663
    /// expression.
3664
    ///
3665
    /// This is a binary operator, which applies component-wise to vector
3666
    /// operand expressions. That is, for vectors, this produces a vector of
3667
    /// random values where each component is uniformly distributed within the
3668
    /// bounds of the related component of both operands.
3669
    ///
3670
    /// # Example
3671
    ///
3672
    /// ```
3673
    /// # use bevy_hanabi::*;
3674
    /// # use bevy::math::Vec3;
3675
    /// # let mut w = ExprWriter::new();
3676
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3677
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3678
    ///
3679
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3680
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3681
    ///
3682
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3683
    /// let z = x.uniform(y);
3684
    /// ```
3685
    #[inline]
3686
    pub fn uniform(self, other: Self) -> Self {
×
3687
        self.binary_op(other, BinaryOperator::UniformRand)
×
3688
    }
3689

3690
    /// Apply the logical operator "normal" to this expression and another
3691
    /// expression.
3692
    ///
3693
    /// This is a binary operator, which applies component-wise to vector
3694
    /// operand expressions. That is, for vectors, this produces a vector of
3695
    /// random values where each component is normally distributed with a mean
3696
    /// of the corresponding component of the first operand and a standard
3697
    /// deviation of the corresponding component of the second operand.
3698
    ///
3699
    /// # Example
3700
    ///
3701
    /// ```
3702
    /// # use bevy_hanabi::*;
3703
    /// # use bevy::math::Vec3;
3704
    /// # let mut w = ExprWriter::new();
3705
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3706
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3707
    ///
3708
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3709
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3710
    ///
3711
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3712
    /// let z = x.normal(y);
3713
    /// ```
3714
    #[inline]
3715
    pub fn normal(self, other: Self) -> Self {
×
3716
        self.binary_op(other, BinaryOperator::NormalRand)
×
3717
    }
3718

3719
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3720
        assert_eq!(self.module, second.module);
×
3721
        assert_eq!(self.module, third.module);
×
3722
        let first = self.expr;
×
3723
        let second = second.expr;
×
3724
        let third = third.expr;
×
3725
        let expr = self.module.borrow_mut().push(Expr::Ternary {
×
3726
            op,
×
3727
            first,
×
3728
            second,
×
3729
            third,
×
3730
        });
3731
        WriterExpr {
3732
            expr,
3733
            module: self.module,
×
3734
        }
3735
    }
3736

3737
    /// Blending linearly ("mix") two expressions with the fraction provided by
3738
    /// a third expression.
3739
    ///
3740
    /// This is a ternary operator, which applies component-wise to vector
3741
    /// operand expressions.
3742
    ///
3743
    /// # Example
3744
    ///
3745
    /// ```
3746
    /// # use bevy_hanabi::*;
3747
    /// # use bevy::math::Vec2;
3748
    /// # let mut w = ExprWriter::new();
3749
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3750
    /// let x = w.lit(Vec2::new(3., -2.));
3751
    ///
3752
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3753
    /// let y = w.lit(Vec2::new(1., 4.));
3754
    ///
3755
    /// // A fraction `t = 0.5;`.
3756
    /// let t = w.lit(0.25);
3757
    ///
3758
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3759
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3760
    /// ```
3761
    #[inline]
3762
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3763
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3764
    }
3765

3766
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3767
    /// value taken between the given bounds.
3768
    ///
3769
    /// This is a ternary operator, which applies component-wise to vector
3770
    /// operand expressions.
3771
    ///
3772
    /// # Example
3773
    ///
3774
    /// ```
3775
    /// # use bevy_hanabi::*;
3776
    /// # use bevy::math::Vec2;
3777
    /// # let mut w = ExprWriter::new();
3778
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3779
    /// let low = w.lit(Vec2::new(3., -2.));
3780
    ///
3781
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3782
    /// let high = w.lit(Vec2::new(1., 4.));
3783
    ///
3784
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3785
    /// let x = w.lit(Vec2::new(2., 1.));
3786
    ///
3787
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3788
    /// let t = x.smoothstep(low, high); // == 0.5
3789
    /// ```
3790
    #[inline]
3791
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3792
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3793
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3794
    }
3795

3796
    /// Construct a `Vec2` from two scalars.
3797
    ///
3798
    /// # Example
3799
    ///
3800
    /// ```
3801
    /// # use bevy_hanabi::*;
3802
    /// # let mut w = ExprWriter::new();
3803
    /// let theta = w.add_property("theta", 0.0.into());
3804
    /// // Convert the angular property `theta` to a 2D vector.
3805
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3806
    /// let circle_pos = cos_theta.vec2(sin_theta);
3807
    /// ```
3808
    #[inline]
3809
    pub fn vec2(self, y: Self) -> Self {
×
3810
        self.binary_op(y, BinaryOperator::Vec2)
×
3811
    }
3812

3813
    /// Construct a `Vec3` from two scalars.
3814
    ///
3815
    /// # Example
3816
    ///
3817
    /// ```
3818
    /// # use bevy_hanabi::*;
3819
    /// # let mut w = ExprWriter::new();
3820
    /// let theta = w.add_property("theta", 0.0.into());
3821
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
3822
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3823
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
3824
    /// ```
3825
    #[inline]
3826
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
3827
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
3828
    }
3829

3830
    /// Construct a `Vec4` from a vector XYZ and a scalar W.
3831
    ///
3832
    /// # Example
3833
    ///
3834
    /// ```
3835
    /// # use bevy_hanabi::*;
3836
    /// # let mut w = ExprWriter::new();
3837
    /// let rgb = w.rand(VectorType::VEC3F);
3838
    /// let a = w.lit(1.);
3839
    /// // Build vec4<f32>(R, G, B, A) and convert to 0xAABBGGRR
3840
    /// let col = rgb.vec4_xyz_w(a).Pack4x8unorm();
3841
    /// ```
3842
    #[inline]
NEW
3843
    pub fn vec4_xyz_w(self, w: Self) -> Self {
×
NEW
3844
        self.binary_op(w, BinaryOperator::Vec4XyzW)
×
3845
    }
3846

3847
    /// Cast an expression to a different type.
3848
    ///
3849
    /// # Example
3850
    ///
3851
    /// ```
3852
    /// # use bevy_hanabi::*;
3853
    /// # use bevy::math::Vec2;
3854
    /// # let mut w = ExprWriter::new();
3855
    /// let x = w.lit(Vec2::new(3., -2.));
3856
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
3857
    /// ```
3858
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
3859
        let target = target.into();
×
3860
        let expr = self
×
3861
            .module
×
3862
            .borrow_mut()
3863
            .push(Expr::Cast(CastExpr::new(self.expr, target)));
×
3864
        WriterExpr {
3865
            expr,
3866
            module: self.module,
×
3867
        }
3868
    }
3869

3870
    /// Finalize an expression chain and return the accumulated expression.
3871
    ///
3872
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
3873
    /// this intermediate expression was built from.
3874
    ///
3875
    /// # Example
3876
    ///
3877
    /// ```
3878
    /// # use bevy_hanabi::*;
3879
    /// # let mut w = ExprWriter::new();
3880
    /// // A literal expression `x = -3.5;`.
3881
    /// let x = w.lit(-3.5);
3882
    ///
3883
    /// // Retrieve the ExprHandle for that expression.
3884
    /// let handle = x.expr();
3885
    /// ```
3886
    #[inline]
3887
    pub fn expr(self) -> ExprHandle {
8✔
3888
        self.expr
8✔
3889
    }
3890
}
3891

3892
impl std::ops::Add<WriterExpr> for WriterExpr {
3893
    type Output = WriterExpr;
3894

3895
    #[inline]
3896
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
3897
        self.add(rhs)
2✔
3898
    }
3899
}
3900

3901
impl std::ops::Sub<WriterExpr> for WriterExpr {
3902
    type Output = WriterExpr;
3903

3904
    #[inline]
3905
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
3906
        self.sub(rhs)
×
3907
    }
3908
}
3909

3910
impl std::ops::Mul<WriterExpr> for WriterExpr {
3911
    type Output = WriterExpr;
3912

3913
    #[inline]
3914
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
3915
        self.mul(rhs)
1✔
3916
    }
3917
}
3918

3919
impl std::ops::Div<WriterExpr> for WriterExpr {
3920
    type Output = WriterExpr;
3921

3922
    #[inline]
3923
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
3924
        self.div(rhs)
×
3925
    }
3926
}
3927

3928
impl std::ops::Rem<WriterExpr> for WriterExpr {
3929
    type Output = WriterExpr;
3930

3931
    #[inline]
3932
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
3933
        self.rem(rhs)
×
3934
    }
3935
}
3936

3937
#[cfg(test)]
3938
mod tests {
3939
    use bevy::{prelude::*, utils::HashSet};
3940

3941
    use super::*;
3942
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
3943

3944
    #[test]
3945
    fn module() {
3946
        let mut m = Module::default();
3947

3948
        #[allow(unsafe_code)]
3949
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
3950
        assert!(m.get(unknown).is_none());
3951
        assert!(m.get_mut(unknown).is_none());
3952
        assert!(matches!(
3953
            m.try_get(unknown),
3954
            Err(ExprError::InvalidExprHandleError(_))
3955
        ));
3956
        assert!(matches!(
3957
            m.try_get_mut(unknown),
3958
            Err(ExprError::InvalidExprHandleError(_))
3959
        ));
3960

3961
        let x = m.lit(5.);
3962
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
3963
        assert_eq!(m.get(x), Some(&expected));
3964
        assert_eq!(m.get_mut(x), Some(&mut expected));
3965
        assert_eq!(m.try_get(x), Ok(&expected));
3966
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
3967
    }
3968

3969
    #[test]
3970
    fn local_var() {
3971
        let property_layout = PropertyLayout::default();
3972
        let particle_layout = ParticleLayout::default();
3973
        let mut ctx =
3974
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3975
        let mut h = HashSet::new();
3976
        for _ in 0..100 {
3977
            let v = ctx.make_local_var();
3978
            assert!(h.insert(v));
3979
        }
3980
    }
3981

3982
    #[test]
3983
    fn make_fn() {
3984
        let property_layout = PropertyLayout::default();
3985
        let particle_layout = ParticleLayout::default();
3986
        let mut ctx =
3987
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3988
        let mut module = Module::default();
3989

3990
        // Make a function
3991
        let func_name = "my_func";
3992
        let args = "arg0: i32, arg1: f32";
3993
        assert!(ctx
3994
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
3995
                m.lit(3.);
3996
                let v = ctx.make_local_var();
3997
                assert_eq!(v, "var0");
3998
                let code = String::new();
3999
                Ok(code)
4000
            })
4001
            .is_ok());
4002

4003
        // The local function context doesn't influence the outer caller context
4004
        let v = ctx.make_local_var();
4005
        assert_eq!(v, "var0");
4006

4007
        // However the module is common to the outer caller and the function
4008
        assert!(!module.expressions.is_empty());
4009
    }
4010

4011
    #[test]
4012
    fn property() {
4013
        let mut m = Module::default();
4014

4015
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
4016
        let _other_prop = m.add_property(
4017
            "other_prop",
4018
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
4019
        );
4020

4021
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
4022
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
4023
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
4024
    }
4025

4026
    #[test]
4027
    fn writer() {
4028
        // Get a module and its writer
4029
        let w = ExprWriter::new();
4030
        let my_prop = w.add_property("my_prop", 3.0.into());
4031

4032
        // Build some expression
4033
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
4034
            + w.lit(-4.).min(w.prop(my_prop));
4035
        let x = x.expr();
4036

4037
        // Create an evaluation context
4038
        let property_layout =
4039
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
4040
        let particle_layout = ParticleLayout::default();
4041
        let m = w.finish();
4042
        let mut context =
4043
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4044

4045
        // Evaluate the expression
4046
        let x = m.try_get(x).unwrap();
4047
        let s = x.eval(&m, &mut context).unwrap();
4048
        assert_eq!(
4049
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties.my_prop))"
4050
                .to_string(),
4051
            s
4052
        );
4053
    }
4054

4055
    #[test]
4056
    fn type_error() {
4057
        let l = Value::Scalar(3.5_f32.into());
4058
        let r: Result<Vec2, ExprError> = l.try_into();
4059
        assert!(r.is_err());
4060
        assert!(matches!(r, Err(ExprError::TypeError(_))));
4061
    }
4062

4063
    #[test]
4064
    fn math_expr() {
4065
        let mut m = Module::default();
4066

4067
        let x = m.attr(Attribute::POSITION);
4068
        let y = m.lit(Vec3::ONE);
4069

4070
        let add = m.add(x, y);
4071
        let sub = m.sub(x, y);
4072
        let mul = m.mul(x, y);
4073
        let div = m.div(x, y);
4074
        let rem = m.rem(x, y);
4075
        let lt = m.lt(x, y);
4076
        let le = m.le(x, y);
4077
        let gt = m.gt(x, y);
4078
        let ge = m.ge(x, y);
4079

4080
        let property_layout = PropertyLayout::default();
4081
        let particle_layout = ParticleLayout::default();
4082
        let mut ctx =
4083
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4084

4085
        for (expr, op) in [
4086
            (add, "+"),
4087
            (sub, "-"),
4088
            (mul, "*"),
4089
            (div, "/"),
4090
            (rem, "%"),
4091
            (lt, "<"),
4092
            (le, "<="),
4093
            (gt, ">"),
4094
            (ge, ">="),
4095
        ] {
4096
            let expr = ctx.eval(&m, expr);
4097
            assert!(expr.is_ok());
4098
            let expr = expr.unwrap();
4099
            assert_eq!(
4100
                expr,
4101
                format!(
4102
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
4103
                    Attribute::POSITION.name(),
4104
                    op,
4105
                )
4106
            );
4107
        }
4108
    }
4109

4110
    #[test]
4111
    fn builtin_expr() {
4112
        let mut m = Module::default();
4113

4114
        // Simulation parameters
4115
        for op in [
4116
            BuiltInOperator::Time,
4117
            BuiltInOperator::DeltaTime,
4118
            BuiltInOperator::VirtualTime,
4119
            BuiltInOperator::VirtualDeltaTime,
4120
            BuiltInOperator::RealTime,
4121
            BuiltInOperator::RealDeltaTime,
4122
        ] {
4123
            let value = m.builtin(op);
4124

4125
            let property_layout = PropertyLayout::default();
4126
            let particle_layout = ParticleLayout::default();
4127
            let mut ctx =
4128
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4129

4130
            let expr = ctx.eval(&m, value);
4131
            assert!(expr.is_ok());
4132
            let expr = expr.unwrap();
4133
            assert_eq!(expr, format!("sim_params.{}", op.name()));
4134
        }
4135

4136
        // is_alive
4137
        {
4138
            let value = m.builtin(BuiltInOperator::IsAlive);
4139

4140
            let property_layout = PropertyLayout::default();
4141
            let particle_layout = ParticleLayout::default();
4142
            let mut ctx =
4143
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4144

4145
            let expr = ctx.eval(&m, value);
4146
            assert!(expr.is_ok());
4147
            let expr = expr.unwrap();
4148
            assert_eq!(expr, "is_alive");
4149
        }
4150

4151
        // BuiltInOperator::Rand (which has side effect)
4152
        for (scalar_type, prefix) in [
4153
            (ScalarType::Bool, "b"),
4154
            (ScalarType::Float, "f"),
4155
            (ScalarType::Int, "i"),
4156
            (ScalarType::Uint, "u"),
4157
        ] {
4158
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
4159

4160
            // Scalar form
4161
            {
4162
                let property_layout = PropertyLayout::default();
4163
                let particle_layout = ParticleLayout::default();
4164
                let mut ctx =
4165
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4166

4167
                let expr = ctx.eval(&m, value);
4168
                assert!(expr.is_ok());
4169
                let expr = expr.unwrap();
4170
                assert_eq!(expr, "var0");
4171
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
4172
            }
4173

4174
            // Vector form
4175
            for count in 2..=4 {
4176
                let vec = m.builtin(BuiltInOperator::Rand(
4177
                    VectorType::new(scalar_type, count).into(),
4178
                ));
4179

4180
                let property_layout = PropertyLayout::default();
4181
                let particle_layout = ParticleLayout::default();
4182
                let mut ctx =
4183
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4184

4185
                let expr = ctx.eval(&m, vec);
4186
                assert!(expr.is_ok());
4187
                let expr = expr.unwrap();
4188
                assert_eq!(expr, "var0");
4189
                assert_eq!(
4190
                    ctx.main_code,
4191
                    format!("let var0 = {}rand{}();\n", prefix, count)
4192
                );
4193
            }
4194
        }
4195
    }
4196

4197
    #[test]
4198
    fn unary_expr() {
4199
        let mut m = Module::default();
4200

4201
        let x = m.attr(Attribute::POSITION);
4202
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
4203
        let z = m.lit(BVec3::new(false, true, false));
4204
        let w = m.lit(Vec4::W);
4205
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
4206
        let us = m.lit(0x0u32);
4207
        let uu = m.lit(0x0u32);
4208

4209
        let abs = m.abs(x);
4210
        let acos = m.acos(w);
4211
        let all = m.all(z);
4212
        let any = m.any(z);
4213
        let asin = m.asin(w);
4214
        let atan = m.atan(w);
4215
        let ceil = m.ceil(y);
4216
        let cos = m.cos(y);
4217
        let exp = m.exp(y);
4218
        let exp2 = m.exp2(y);
4219
        let floor = m.floor(y);
4220
        let fract = m.fract(y);
4221
        let inv_sqrt = m.inverse_sqrt(y);
4222
        let length = m.length(y);
4223
        let log = m.log(y);
4224
        let log2 = m.log2(y);
4225
        let norm = m.normalize(y);
4226
        let pack4x8snorm = m.pack4x8snorm(v);
4227
        let pack4x8unorm = m.pack4x8unorm(v);
4228
        let round = m.round(y);
4229
        let saturate = m.saturate(y);
4230
        let sign = m.sign(y);
4231
        let sin = m.sin(y);
4232
        let sqrt = m.sqrt(y);
4233
        let tan = m.tan(y);
4234
        let unpack4x8snorm = m.unpack4x8snorm(us);
4235
        let unpack4x8unorm = m.unpack4x8unorm(uu);
4236
        let comp_x = m.x(w);
4237
        let comp_y = m.y(w);
4238
        let comp_z = m.z(w);
4239
        let comp_w = m.w(w);
4240

4241
        let property_layout = PropertyLayout::default();
4242
        let particle_layout = ParticleLayout::default();
4243
        let mut ctx =
4244
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4245

4246
        for (expr, op, inner) in [
4247
            (
4248
                abs,
4249
                "abs",
4250
                &format!("particle.{}", Attribute::POSITION.name())[..],
4251
            ),
4252
            (acos, "acos", "vec4<f32>(0.,0.,0.,1.)"),
4253
            (all, "all", "vec3<bool>(false,true,false)"),
4254
            (any, "any", "vec3<bool>(false,true,false)"),
4255
            (asin, "asin", "vec4<f32>(0.,0.,0.,1.)"),
4256
            (atan, "atan", "vec4<f32>(0.,0.,0.,1.)"),
4257
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
4258
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
4259
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
4260
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
4261
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
4262
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
4263
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
4264
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
4265
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
4266
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
4267
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
4268
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4269
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4270
            (round, "round", "vec3<f32>(1.,-3.1,6.99)"),
4271
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4272
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4273
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4274
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4275
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4276
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4277
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4278
        ] {
4279
            let expr = ctx.eval(&m, expr);
4280
            assert!(expr.is_ok());
4281
            let expr = expr.unwrap();
4282
            assert_eq!(expr, format!("{}({})", op, inner));
4283
        }
4284

4285
        for (expr, op, inner) in [
4286
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4287
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4288
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4289
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4290
        ] {
4291
            let expr = ctx.eval(&m, expr);
4292
            assert!(expr.is_ok());
4293
            let expr = expr.unwrap();
4294
            assert_eq!(expr, format!("{}.{}", inner, op));
4295
        }
4296
    }
4297

4298
    #[test]
4299
    fn binary_expr() {
4300
        let mut m = Module::default();
4301

4302
        let x = m.attr(Attribute::POSITION);
4303
        let y = m.lit(Vec3::ONE);
4304

4305
        let atan2 = m.atan2(x, y);
4306
        let cross = m.cross(x, y);
4307
        let dist = m.distance(x, y);
4308
        let dot = m.dot(x, y);
4309
        let min = m.min(x, y);
4310
        let max = m.max(x, y);
4311
        let step = m.step(x, y);
4312

4313
        let property_layout = PropertyLayout::default();
4314
        let particle_layout = ParticleLayout::default();
4315
        let mut ctx =
4316
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4317

4318
        for (expr, op) in [
4319
            (atan2, "atan2"),
4320
            (cross, "cross"),
4321
            (dist, "distance"),
4322
            (dot, "dot"),
4323
            (min, "min"),
4324
            (max, "max"),
4325
            (step, "step"),
4326
        ] {
4327
            let expr = ctx.eval(&m, expr);
4328
            assert!(expr.is_ok());
4329
            let expr = expr.unwrap();
4330
            assert_eq!(
4331
                expr,
4332
                format!(
4333
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4334
                    op,
4335
                    Attribute::POSITION.name(),
4336
                )
4337
            );
4338
        }
4339
    }
4340

4341
    #[test]
4342
    fn ternary_expr() {
4343
        let mut m = Module::default();
4344

4345
        let x = m.attr(Attribute::POSITION);
4346
        let y = m.lit(Vec3::ONE);
4347
        let t = m.lit(0.3);
4348

4349
        let mix = m.mix(x, y, t);
4350
        let smoothstep = m.smoothstep(x, y, x);
4351

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

4357
        for (expr, op, third) in [(mix, "mix", t), (smoothstep, "smoothstep", x)] {
4358
            let expr = ctx.eval(&m, expr);
4359
            assert!(expr.is_ok());
4360
            let expr = expr.unwrap();
4361
            let third = ctx.eval(&m, third).unwrap();
4362
            assert_eq!(
4363
                expr,
4364
                format!(
4365
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4366
                    op,
4367
                    Attribute::POSITION.name(),
4368
                    third
4369
                )
4370
            );
4371
        }
4372
    }
4373

4374
    #[test]
4375
    fn cast_expr() {
4376
        let mut m = Module::default();
4377

4378
        let x = m.attr(Attribute::POSITION);
4379
        let y = m.lit(IVec2::ONE);
4380
        let z = m.lit(0.3);
4381
        let w = m.lit(false);
4382

4383
        let cx = m.cast(x, VectorType::VEC3I);
4384
        let cy = m.cast(y, VectorType::VEC2U);
4385
        let cz = m.cast(z, ScalarType::Int);
4386
        let cw = m.cast(w, ScalarType::Uint);
4387

4388
        let property_layout = PropertyLayout::default();
4389
        let particle_layout = ParticleLayout::default();
4390
        let mut ctx =
4391
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4392

4393
        for (expr, cast, target) in [
4394
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4395
            (y, cy, VectorType::VEC2U.into()),
4396
            (z, cz, ScalarType::Int.into()),
4397
            (w, cw, ScalarType::Uint.into()),
4398
        ] {
4399
            let expr = ctx.eval(&m, expr);
4400
            assert!(expr.is_ok());
4401
            let expr = expr.unwrap();
4402
            let cast = ctx.eval(&m, cast);
4403
            assert!(cast.is_ok());
4404
            let cast = cast.unwrap();
4405
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4406
        }
4407
    }
4408

4409
    #[test]
4410
    fn attribute_pointer() {
4411
        let mut m = Module::default();
4412
        let x = m.attr(Attribute::POSITION);
4413

4414
        let property_layout = PropertyLayout::default();
4415
        let particle_layout = ParticleLayout::default();
4416
        let mut ctx =
4417
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4418

4419
        let res = ctx.eval(&m, x);
4420
        assert!(res.is_ok());
4421
        let xx = res.ok().unwrap();
4422
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4423

4424
        // Use a different context; it's invalid to reuse a mutated context, as the
4425
        // expression cache will have been generated with the wrong context.
4426
        let mut ctx =
4427
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4428
                .with_attribute_pointer();
4429

4430
        let res = ctx.eval(&m, x);
4431
        assert!(res.is_ok());
4432
        let xx = res.ok().unwrap();
4433
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4434
    }
4435

4436
    #[test]
4437
    #[should_panic]
4438
    fn invalid_cast_vector_to_scalar() {
4439
        let mut m = Module::default();
4440
        let x = m.lit(Vec2::ONE);
4441
        let _ = m.cast(x, ScalarType::Float);
4442
    }
4443

4444
    #[test]
4445
    #[should_panic]
4446
    fn invalid_cast_matrix_to_scalar() {
4447
        let mut m = Module::default();
4448
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4449
        let _ = m.cast(x, ScalarType::Float);
4450
    }
4451

4452
    #[test]
4453
    #[should_panic]
4454
    fn invalid_cast_matrix_to_vector() {
4455
        let mut m = Module::default();
4456
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4457
        let _ = m.cast(x, VectorType::VEC4F);
4458
    }
4459

4460
    #[test]
4461
    #[should_panic]
4462
    fn invalid_cast_scalar_to_matrix() {
4463
        let mut m = Module::default();
4464
        let x = m.lit(3.);
4465
        let _ = m.cast(x, MatrixType::MAT3X3F);
4466
    }
4467

4468
    #[test]
4469
    #[should_panic]
4470
    fn invalid_cast_vector_to_matrix() {
4471
        let mut m = Module::default();
4472
        let x = m.lit(Vec3::ZERO);
4473
        let _ = m.cast(x, MatrixType::MAT2X4F);
4474
    }
4475

4476
    #[test]
4477
    fn cast_expr_new() {
4478
        let mut m = Module::default();
4479

4480
        let x = m.attr(Attribute::POSITION);
4481
        let c = CastExpr::new(x, VectorType::VEC3F);
4482
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4483
        assert_eq!(c.is_valid(&m), Some(true));
4484

4485
        let x = m.attr(Attribute::POSITION);
4486
        let c = CastExpr::new(x, ScalarType::Bool);
4487
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4488
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4489

4490
        let p = m.add_property("my_prop", 3.0.into());
4491
        let y = m.prop(p);
4492
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4493
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4494
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4495
    }
4496

4497
    #[test]
4498
    fn side_effect() {
4499
        let mut m = Module::default();
4500

4501
        // Adding the same cloned expression with side effect to itself should yield
4502
        // twice the value, and not two separate evaluations of the expression.
4503
        // CORRECT:
4504
        //   let r = frand();
4505
        //   r + r
4506
        // INCORRECT:
4507
        //   frand() + frand()
4508

4509
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4510
        let r2 = r;
4511
        let r3 = r2;
4512
        let a = m.add(r, r2);
4513
        let b = m.mix(r, r2, r3);
4514
        let c = m.abs(a);
4515

4516
        {
4517
            let property_layout = PropertyLayout::default();
4518
            let particle_layout = ParticleLayout::default();
4519
            let mut ctx =
4520
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4521
            let value = ctx.eval(&m, a).unwrap();
4522
            assert_eq!(value, "(var0) + (var0)");
4523
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4524
        }
4525

4526
        {
4527
            let property_layout = PropertyLayout::default();
4528
            let particle_layout = ParticleLayout::default();
4529
            let mut ctx =
4530
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4531
            let value = ctx.eval(&m, b).unwrap();
4532
            assert_eq!(value, "mix(var0, var0, var0)");
4533
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4534
        }
4535

4536
        {
4537
            let property_layout = PropertyLayout::default();
4538
            let particle_layout = ParticleLayout::default();
4539
            let mut ctx =
4540
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4541
            let value = ctx.eval(&m, c).unwrap();
4542
            assert_eq!(value, "abs((var0) + (var0))");
4543
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4544
        }
4545
    }
4546

4547
    // #[test]
4548
    // fn serde() {
4549
    //     let v = Value::Scalar(3.0_f32.into());
4550
    //     let l: LiteralExpr = v.into();
4551
    //     assert_eq!(Ok(v), l.eval());
4552
    //     let s = ron::to_string(&l).unwrap();
4553
    //     println!("literal: {:?}", s);
4554
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4555
    //     assert_eq!(l_serde, l);
4556

4557
    //     let b: ExprHandle = Box::new(l);
4558
    //     let s = ron::to_string(&b).unwrap();
4559
    //     println!("boxed literal: {:?}", s);
4560
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4561
    //     assert!(b_serde.is_const());
4562
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4563

4564
    //     let v0 = Value::Scalar(3.0_f32.into());
4565
    //     let v1 = Value::Scalar(2.5_f32.into());
4566
    //     let l0: LiteralExpr = v0.into();
4567
    //     let l1: LiteralExpr = v1.into();
4568
    //     let a = l0 + l1;
4569
    //     assert!(a.is_const());
4570
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4571
    //     let s = ron::to_string(&a).unwrap();
4572
    //     println!("add: {:?}", s);
4573
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4574
    //     println!("a_serde: {:?}", a_serde);
4575
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4576
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4577
    // }
4578
}
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