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

djeedai / bevy_hanabi / 13640457354

03 Mar 2025 09:09PM UTC coverage: 40.055% (-6.7%) from 46.757%
13640457354

push

github

web-flow
Hierarchical effects and GPU spawn event (#424)

This change introduces hierarchical effects, the ability of an effect to
be parented to another effect through the `EffectParent` component.
Child effects can inherit attributes from their parent when spawned
during the init pass, but are otherwise independent effects. They
replace the old group system, which is entirely removed. The parent
effect can emit GPU spawn events, which are consumed by the child effect
to spawn particles instead of the traditional CPU spawn count. Those GPU
spawn events currently are just the ID of the parent particles, to allow
read-only access to its attribute in _e.g._ the new
`InheritAttributeModifier`.

The ribbon/trail system is also reworked. The atomic linked list based
on `Attribute::PREV` and `Attribute::NEXT` is abandoned, and replaced
with an explicit sort compute pass which orders particles by
`Attribute::RIBBON_ID` first, and `Attribute::AGE` next. The ribbon ID
is any `u32` value unique to each ribbon/trail. Sorting particles by age
inside a given ribbon/trail allows avoiding the edge case where a
particle in the middle of a trail dies, leaving a gap in the list.

A migration guide is provided from v0.14 to the upcoming v0.15 which
will include this change, due to the large change of behavior and APIs.

409 of 2997 new or added lines in 17 files covered. (13.65%)

53 existing lines in 11 files now uncovered.

3208 of 8009 relevant lines covered (40.05%)

18.67 hits per line

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

52.99
/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 {
228✔
147
        debug_assert!(id != 0);
456✔
148
        Self {
149
            id: NonZeroU32::new_unchecked(id as u32),
228✔
150
        }
151
    }
152

153
    /// Get the zero-based index into the array of the module.
154
    fn index(&self) -> usize {
384✔
155
        (self.id.get() - 1) as usize
384✔
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 {
34✔
272
            self.unary(UnaryOperator::$T, inner)
34✔
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 {
33✔
282
            self.binary(BinaryOperator::$T, left, right)
33✔
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 {
227✔
397
        self.expressions.push(expr.into());
227✔
398
        #[allow(unsafe_code)]
227✔
399
        unsafe {
400
            ExprHandle::new_unchecked(self.expressions.len())
227✔
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]
NEW
421
    pub fn parent_attr(&mut self, attr: Attribute) -> ExprHandle {
×
NEW
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 {
34✔
456
        assert!(inner.index() < self.expressions.len());
34✔
457
        self.push(Expr::Unary { op, expr: inner })
34✔
458
    }
459

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

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

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

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

568
    impl_module_ternary!(mix, Mix);
569
    impl_module_ternary!(smoothstep, SmoothStep);
570

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

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

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

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

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

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

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

659
    /// Get the texture layout of this module.
660
    pub fn texture_layout(&self) -> TextureLayout {
25✔
661
        self.texture_layout.clone()
25✔
662
    }
663
}
664

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

677
    /// Expression syntax error.
678
    #[error("Syntax error: {0}")]
679
    SyntaxError(String),
680

681
    /// Generic graph evaluation error.
682
    #[error("Graph evaluation error: {0}")]
683
    GraphEvalError(String),
684

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

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

704
    /// Invalid modifier context.
705
    ///
706
    /// The operation was expecting a given [`ModifierContext`], but instead
707
    /// another [`ModifierContext`] was available.
708
    #[error("Invalid modifier context {0}, expected {1} instead.")]
709
    InvalidModifierContext(ModifierContext, ModifierContext),
710
}
711

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

728
    /// Get the particle layout of the effect.
729
    fn particle_layout(&self) -> &ParticleLayout;
730

731
    /// Get the property layout of the effect.
732
    fn property_layout(&self) -> &PropertyLayout;
733

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

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

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

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

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

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

802
    /// Literal expression ([`LiteralExpr`]).
803
    ///
804
    /// A literal expression represents a shader constants.
805
    Literal(LiteralExpr),
806

807
    /// Property expression ([`PropertyExpr`]).
808
    ///
809
    /// A property expression represents the value of an [`EffectAsset`]'s
810
    /// property.
811
    ///
812
    /// [`EffectAsset`]: crate::EffectAsset
813
    Property(PropertyExpr),
814

815
    /// Attribute expression ([`AttributeExpr`]).
816
    ///
817
    /// An attribute expression represents the value of an attribute for a
818
    /// particle, like its position or velocity.
819
    Attribute(AttributeExpr),
820

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

834
    /// Unary operation expression.
835
    ///
836
    /// A unary operation transforms an expression into another expression.
837
    Unary {
838
        /// Unary operator.
839
        op: UnaryOperator,
840
        /// Operand the unary operation applies to.
841
        expr: ExprHandle,
842
    },
843

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

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

870
    /// Cast expression.
871
    ///
872
    /// An expression to cast an expression to another type.
873
    Cast(CastExpr),
874

875
    /// Access to textures.
876
    ///
877
    /// An expression to sample a texture from the effect's material. Currently
878
    /// only color textures (returning a `vec4<f32>`) are supported.
879
    TextureSample(TextureSampleExpr),
880
}
881

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

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

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

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

1032
                // if expr.value_type() != self.value_type() {
1033
                //     return Err(ExprError::TypeError(format!(
1034
                //         "Cannot apply normalize() function to non-vector expression: {}",
1035
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1036
                //     )));
1037
                // }
1038

1039
                Ok(if op.is_functional() {
1040
                    format!("{}({})", op.to_wgsl_string(), expr)
30✔
1041
                } else {
1042
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1043
                })
1044
            }
1045
            Expr::Binary { op, left, right } => {
38✔
1046
                // Recursively evaluate child expressions throught the context to ensure caching
1047
                let compiled_left = context.eval(module, *left)?;
76✔
1048
                let compiled_right = context.eval(module, *right)?;
38✔
1049

1050
                // if !self.input.value_type().is_vector() {
1051
                //     return Err(ExprError::TypeError(format!(
1052
                //         "Cannot apply normalize() function to non-vector expression: {}",
1053
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1054
                //     )));
1055
                // }
1056

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

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

1123
                // if !self.input.value_type().is_vector() {
1124
                //     return Err(ExprError::TypeError(format!(
1125
                //         "Cannot apply normalize() function to non-vector expression: {}",
1126
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1127
                //     )));
1128
                // }
1129

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

1142
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
1143
            }
1144
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1145
        }
1146
    }
1147
}
1148

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

1162
impl LiteralExpr {
1163
    /// Create a new literal expression from a [`Value`].
1164
    pub fn new<V>(value: V) -> Self
76✔
1165
    where
1166
        Value: From<V>,
1167
    {
1168
        Self {
1169
            value: value.into(),
76✔
1170
        }
1171
    }
1172

1173
    /// Is the expression resulting in a compile-time constant which can be
1174
    /// hard-coded into a shader's code?
1175
    pub fn is_const(&self) -> bool {
×
1176
        true
×
1177
    }
1178

1179
    /// Get the value type of the expression.
1180
    pub fn value_type(&self) -> ValueType {
17✔
1181
        self.value.value_type()
17✔
1182
    }
1183

1184
    /// Evaluate the expression in the given context.
1185
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
96✔
1186
        Ok(self.value.to_wgsl_string())
96✔
1187
    }
1188
}
1189

1190
impl ToWgslString for LiteralExpr {
1191
    fn to_wgsl_string(&self) -> String {
×
1192
        self.value.to_wgsl_string()
×
1193
    }
1194
}
1195

1196
impl From<&Value> for LiteralExpr {
1197
    fn from(value: &Value) -> Self {
×
1198
        Self { value: *value }
×
1199
    }
1200
}
1201

1202
impl<T: Into<Value>> From<T> for LiteralExpr {
1203
    fn from(value: T) -> Self {
×
1204
        Self {
1205
            value: value.into(),
×
1206
        }
1207
    }
1208
}
1209

1210
/// Expression representing the value of an attribute of a particle.
1211
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1212
pub struct AttributeExpr {
1213
    attr: Attribute,
1214
}
1215

1216
impl AttributeExpr {
1217
    /// Create a new attribute expression.
1218
    #[inline]
1219
    pub fn new(attr: Attribute) -> Self {
27✔
1220
        Self { attr }
1221
    }
1222

1223
    /// Is the expression resulting in a compile-time constant which can be
1224
    /// hard-coded into a shader's code?
1225
    pub fn is_const(&self) -> bool {
×
1226
        false
×
1227
    }
1228

1229
    /// Get the value type of the expression.
1230
    pub fn value_type(&self) -> ValueType {
3✔
1231
        self.attr.value_type()
3✔
1232
    }
1233

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

1262
impl ToWgslString for AttributeExpr {
1263
    fn to_wgsl_string(&self) -> String {
×
1264
        format!("particle.{}", self.attr.name())
×
1265
    }
1266
}
1267

1268
impl From<Attribute> for AttributeExpr {
1269
    fn from(value: Attribute) -> Self {
×
1270
        AttributeExpr::new(value)
×
1271
    }
1272
}
1273

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

1289
impl PropertyExpr {
1290
    /// Create a new property expression.
1291
    #[inline]
1292
    pub fn new(property: PropertyHandle) -> Self {
4✔
1293
        Self { property }
1294
    }
1295

1296
    /// Is the expression resulting in a compile-time constant which can be
1297
    /// hard-coded into a shader's code?
1298
    fn is_const(&self) -> bool {
×
1299
        false
×
1300
    }
1301

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

1317
        Ok(format!("properties.{}", prop.name()))
2✔
1318
    }
1319
}
1320

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

1330
impl CastExpr {
1331
    /// Create a new cast expression.
1332
    #[inline]
1333
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1334
        Self {
1335
            inner,
1336
            target: target.into(),
12✔
1337
        }
1338
    }
1339

1340
    /// Get the value type of the expression.
1341
    pub fn value_type(&self) -> ValueType {
3✔
1342
        self.target
3✔
1343
    }
1344

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

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

1401
impl TextureSampleExpr {
1402
    /// Create a new texture sample expression.
1403
    #[inline]
1404
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1405
        Self { image, coordinates }
1406
    }
1407

1408
    /// Get the value type of the expression.
1409
    pub fn value_type(&self) -> ValueType {
×
1410
        // FIXME - depth textures return a single f32 when sampled
1411
        ValueType::Vector(VectorType::VEC4F)
×
1412
    }
1413

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

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

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

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

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

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

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

1605
/// Expression for getting built-in quantities related to the effect system.
1606
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1607
pub struct BuiltInExpr {
1608
    operator: BuiltInOperator,
1609
}
1610

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

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

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

1643
    /// Get the value type of the expression.
1644
    ///
1645
    /// The value type of the expression is the type of the value(s) that an
1646
    /// expression produces.
1647
    pub fn value_type(&self) -> ValueType {
×
1648
        self.operator.value_type()
×
1649
    }
1650

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

1663
impl ToWgslString for BuiltInExpr {
1664
    fn to_wgsl_string(&self) -> String {
37✔
1665
        self.operator.to_wgsl_string()
37✔
1666
    }
1667
}
1668

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

1682
    /// Logical ALL operator for bool vectors.
1683
    ///
1684
    /// Return `true` if all the components of the bool vector operand are
1685
    /// `true`. Invalid for any other type of operand.
1686
    All,
1687

1688
    /// Logical ANY operator for bool vectors.
1689
    ///
1690
    /// Return `true` if any component of the bool vector operand is `true`.
1691
    /// Invalid for any other type of operand.
1692
    Any,
1693

1694
    /// Ceiling operator.
1695
    ///
1696
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1697
    /// `x` is the operand which the operator applies to.
1698
    Ceil,
1699

1700
    /// Cosine operator.
1701
    Cos,
1702

1703
    /// Natural exponent operator.
1704
    ///
1705
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1706
    /// for vectors.
1707
    Exp,
1708

1709
    /// Base-2 exponent operator.
1710
    ///
1711
    /// Return two raised to the power of the operand (`2^x`), component-wise
1712
    /// for vectors.
1713
    Exp2,
1714

1715
    /// Floor operator.
1716
    ///
1717
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1718
    /// `x` is the operand which the operator applies to.
1719
    Floor,
1720

1721
    /// Fractional part operator.
1722
    ///
1723
    /// Return the fractional part of the operand, which is equal to `x -
1724
    /// floor(x)`, component-wise for vectors.
1725
    Fract,
1726

1727
    /// Inverse square root operator.
1728
    ///
1729
    /// Return the inverse square root of the floating-point operand (`1.0 /
1730
    /// sqrt(x)`), component-wise for vectors.
1731
    InvSqrt,
1732

1733
    /// Length operator.
1734
    ///
1735
    /// Return the length of a floating point scalar or vector. The "length" of
1736
    /// a scalar is taken as its absolute value. The length of a vector is the
1737
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1738
    /// squared components).
1739
    ///
1740
    /// The output is always a floating point scalar.
1741
    Length,
1742

1743
    /// Natural logarithm operator.
1744
    ///
1745
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1746
    /// for vectors.
1747
    Log,
1748

1749
    /// Base-2 logarithm operator.
1750
    ///
1751
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1752
    /// for vectors.
1753
    Log2,
1754

1755
    /// Vector normalizing operator.
1756
    ///
1757
    /// Normalize the given numeric vector. Only valid for numeric vector
1758
    /// operands.
1759
    Normalize,
1760

1761
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1762
    ///
1763
    /// Convert the four components of a signed normalized floating point vector
1764
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1765
    /// four values into a single `u32`. Each vector component should be in
1766
    /// `[-1:1]` before packing; values outside this range are clamped.
1767
    Pack4x8snorm,
1768

1769
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1770
    ///
1771
    /// Convert the four components of an unsigned normalized floating point
1772
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1773
    /// those four values into a single `u32`. Each vector component should
1774
    /// be in `[0:1]` before packing; values outside this range are clamped.
1775
    Pack4x8unorm,
1776

1777
    /// Saturate operator.
1778
    ///
1779
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1780
    /// vectors.
1781
    Saturate,
1782

1783
    /// Sign operator.
1784
    ///
1785
    /// Return a value representing the sign of a floating point scalar or
1786
    /// vector input:
1787
    /// - `1.` if the operand is > 0
1788
    /// - `0.` if the operand is = 0
1789
    /// - `-1.` if the operand is < 0
1790
    ///
1791
    /// Applies component-wise for vectors.
1792
    Sign,
1793

1794
    /// Sine operator.
1795
    Sin,
1796

1797
    /// Square root operator.
1798
    ///
1799
    /// Return the square root of the floating-point operand, component-wise for
1800
    /// vectors.
1801
    Sqrt,
1802

1803
    /// Tangent operator.
1804
    Tan,
1805

1806
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1807
    ///
1808
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1809
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1810
    Unpack4x8snorm,
1811

1812
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1813
    ///
1814
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1815
    /// then convert each value to an unsigned normalized `f32` value in
1816
    /// `[0:1]`.
1817
    Unpack4x8unorm,
1818

1819
    /// Get the fourth component of a vector.
1820
    ///
1821
    /// This is only valid for vectors of rank 4.
1822
    W,
1823

1824
    /// Get the first component of a scalar or vector.
1825
    ///
1826
    /// For scalar, return the value itself. For vectors, return the first
1827
    /// component.
1828
    X,
1829

1830
    /// Get the second component of a vector.
1831
    Y,
1832

1833
    /// Get the third component of a vector.
1834
    ///
1835
    /// This is only valid for vectors of rank 3 or more.
1836
    Z,
1837
}
1838

1839
impl UnaryOperator {
1840
    /// Check if a unary operator is called via a functional-style call.
1841
    ///
1842
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
1843
    /// example, while non-functional ones are in the form `inner.op`,
1844
    /// like `v.x` for example. This check is used for formatting the WGSL
1845
    /// code emitted during evaluation of a binary operation expression.
1846
    pub fn is_functional(&self) -> bool {
34✔
1847
        !matches!(
30✔
1848
            *self,
34✔
1849
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
1850
        )
1851
    }
1852
}
1853

1854
impl ToWgslString for UnaryOperator {
1855
    fn to_wgsl_string(&self) -> String {
34✔
1856
        match *self {
34✔
1857
            UnaryOperator::Abs => "abs".to_string(),
5✔
1858
            UnaryOperator::All => "all".to_string(),
1✔
1859
            UnaryOperator::Any => "any".to_string(),
3✔
1860
            UnaryOperator::Ceil => "ceil".to_string(),
1✔
1861
            UnaryOperator::Cos => "cos".to_string(),
1✔
1862
            UnaryOperator::Exp => "exp".to_string(),
1✔
1863
            UnaryOperator::Exp2 => "exp2".to_string(),
1✔
1864
            UnaryOperator::Floor => "floor".to_string(),
1✔
1865
            UnaryOperator::Fract => "fract".to_string(),
1✔
1866
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
1✔
1867
            UnaryOperator::Length => "length".to_string(),
1✔
1868
            UnaryOperator::Log => "log".to_string(),
1✔
1869
            UnaryOperator::Log2 => "log2".to_string(),
1✔
1870
            UnaryOperator::Normalize => "normalize".to_string(),
2✔
1871
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
1✔
1872
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
1✔
1873
            UnaryOperator::Saturate => "saturate".to_string(),
1✔
1874
            UnaryOperator::Sign => "sign".to_string(),
1✔
1875
            UnaryOperator::Sin => "sin".to_string(),
1✔
1876
            UnaryOperator::Sqrt => "sqrt".to_string(),
1✔
1877
            UnaryOperator::Tan => "tan".to_string(),
1✔
1878
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
1✔
1879
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
1✔
1880
            UnaryOperator::W => "w".to_string(),
1✔
1881
            UnaryOperator::X => "x".to_string(),
1✔
1882
            UnaryOperator::Y => "y".to_string(),
1✔
1883
            UnaryOperator::Z => "z".to_string(),
1✔
1884
        }
1885
    }
1886
}
1887

1888
/// Binary operator.
1889
///
1890
/// Operator applied between two operands, generally denoted "left" and "right".
1891
/// The type of the operands and the result are not necessarily the same. Valid
1892
/// operand types depend on the operator itself.
1893
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1894
pub enum BinaryOperator {
1895
    /// Addition operator.
1896
    ///
1897
    /// Returns the sum of its operands. Only valid for numeric operands.
1898
    Add,
1899

1900
    /// Cross product operator.
1901
    ///
1902
    /// Returns the cross product of the left and right operands. Only valid for
1903
    /// vector type operands of size 3. Always produce a vector result of the
1904
    /// same size.
1905
    Cross,
1906

1907
    /// Distance operator.
1908
    ///
1909
    /// Returns the distance between two floating point scalar or vectors, that
1910
    /// is `length(right - left)`.
1911
    Distance,
1912

1913
    /// Division operator.
1914
    ///
1915
    /// Returns the left operand divided by the right operand. Only valid for
1916
    /// numeric operands.
1917
    Div,
1918

1919
    /// Dot product operator.
1920
    ///
1921
    /// Returns the dot product of the left and right operands. Only valid for
1922
    /// vector type operands. Always produce a scalar floating-point result.
1923
    Dot,
1924

1925
    /// Greater-than operator.
1926
    ///
1927
    /// Returns `true` if the left operand is strictly greater than the right
1928
    /// operand. Only valid for numeric types. If the operands are vectors,
1929
    /// they must be of the same rank, and the result is a bool vector of
1930
    /// that rank.
1931
    GreaterThan,
1932

1933
    /// Greater-than-or-equal operator.
1934
    ///
1935
    /// Returns `true` if the left operand is greater than or equal to the right
1936
    /// operand. Only valid for numeric types. If the operands are vectors,
1937
    /// they must be of the same rank, and the result is a bool vector of
1938
    /// that rank.
1939
    GreaterThanOrEqual,
1940

1941
    /// Less-than operator.
1942
    ///
1943
    /// Returns `true` if the left operand is strictly less than the right
1944
    /// operand. Only valid for numeric types. If the operands are vectors,
1945
    /// they must be of the same rank, and the result is a bool vector of
1946
    /// that rank.
1947
    LessThan,
1948

1949
    /// Less-than-or-equal operator.
1950
    ///
1951
    /// Returns `true` if the left operand is less than or equal to the right
1952
    /// operand. Only valid for numeric types. If the operands are vectors,
1953
    /// they must be of the same rank, and the result is a bool vector of
1954
    /// that rank.
1955
    LessThanOrEqual,
1956

1957
    /// Maximum operator.
1958
    ///
1959
    /// Returns the maximum value of its left and right operands. Only valid for
1960
    /// numeric types. If the operands are vectors, they must be of the same
1961
    /// rank, and the result is a vector of that rank and same element
1962
    /// scalar type.
1963
    Max,
1964

1965
    /// Minimum operator.
1966
    ///
1967
    /// Returns the minimum value of its left and right operands. Only valid for
1968
    /// numeric types. If the operands are vectors, they must be of the same
1969
    /// rank, and the result is a vector of that rank and same element
1970
    /// scalar type.
1971
    Min,
1972

1973
    /// Multiply operator.
1974
    ///
1975
    /// Returns the product of its operands. Only valid for numeric operands.
1976
    Mul,
1977

1978
    /// Remainder operator.
1979
    ///
1980
    /// Returns the remainder of the division of the first operand by the
1981
    /// second. Only valid for numeric types. If the operands are vectors,
1982
    /// they must be of the same rank, and the result is a vector of that
1983
    /// rank and same element scalar type.
1984
    Remainder,
1985

1986
    /// Stepping operator.
1987
    ///
1988
    /// Returns `1.0` if the left operand is less than or equal to the right
1989
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
1990
    /// of the same rank, and applied component-wise for vectors.
1991
    Step,
1992

1993
    /// Subtraction operator.
1994
    ///
1995
    /// Returns the difference between its left and right operands. Only valid
1996
    /// for numeric operands.
1997
    Sub,
1998

1999
    /// Uniform random number operator.
2000
    ///
2001
    /// Returns a value generated by a fast non-cryptographically-secure
2002
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2003
    /// are undefined and generally focused around speed. The random value is
2004
    /// uniformly distributed between the left and right operands, which must be
2005
    /// numeric types. If the operands are vectors, they must be of the same
2006
    /// rank, and the result is a vector of that rank and same element
2007
    /// scalar type.
2008
    UniformRand,
2009

2010
    /// Normal distribution random number operator.
2011
    ///
2012
    /// Returns a value generated by a fast non-cryptographically-secure
2013
    /// pseudo-random number generator (PRNG) whose statistical characteristics
2014
    /// are undefined and generally focused around speed. The random value is
2015
    /// normally distributed with mean given by the first operand and standard
2016
    /// deviation by the second, which must be numeric types. If the operands
2017
    /// are vectors, they must be of the same rank, and the result is a vector
2018
    /// of that rank and same element scalar type.
2019
    NormalRand,
2020

2021
    /// Constructor for 2-element vectors.
2022
    ///
2023
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
2024
    /// those two elements `(x, y)`.
2025
    Vec2,
2026
}
2027

2028
impl BinaryOperator {
2029
    /// Check if a binary operator is called via a functional-style call.
2030
    ///
2031
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
2032
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
2033
    /// like `a + b` for example. This check is used for formatting the WGSL
2034
    /// code emitted during evaluation of a binary operation expression.
2035
    pub fn is_functional(&self) -> bool {
38✔
2036
        match *self {
38✔
2037
            BinaryOperator::Add
2038
            | BinaryOperator::Div
2039
            | BinaryOperator::GreaterThan
2040
            | BinaryOperator::GreaterThanOrEqual
2041
            | BinaryOperator::LessThan
2042
            | BinaryOperator::LessThanOrEqual
2043
            | BinaryOperator::Mul
2044
            | BinaryOperator::Remainder
2045
            | BinaryOperator::Sub => false,
27✔
2046
            BinaryOperator::Cross
2047
            | BinaryOperator::Distance
2048
            | BinaryOperator::Dot
2049
            | BinaryOperator::Max
2050
            | BinaryOperator::Min
2051
            | BinaryOperator::Step
2052
            | BinaryOperator::UniformRand
2053
            | BinaryOperator::NormalRand
2054
            | BinaryOperator::Vec2 => true,
11✔
2055
        }
2056
    }
2057

2058
    /// Check if a binary operator needs a type suffix.
2059
    ///
2060
    /// This is currently just for `rand_uniform`
2061
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2062
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2063
    /// WGSL doesn't support user-defined function overloading, so we need a
2064
    /// suffix to disambiguate the types.
2065
    pub fn needs_type_suffix(&self) -> bool {
11✔
2066
        matches!(
11✔
2067
            *self,
11✔
2068
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2069
        )
2070
    }
2071
}
2072

2073
impl ToWgslString for BinaryOperator {
2074
    fn to_wgsl_string(&self) -> String {
38✔
2075
        match *self {
38✔
2076
            BinaryOperator::Add => "+".to_string(),
5✔
2077
            BinaryOperator::Cross => "cross".to_string(),
1✔
2078
            BinaryOperator::Distance => "distance".to_string(),
1✔
2079
            BinaryOperator::Div => "/".to_string(),
2✔
2080
            BinaryOperator::Dot => "dot".to_string(),
1✔
2081
            BinaryOperator::GreaterThan => ">".to_string(),
3✔
2082
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
1✔
2083
            BinaryOperator::LessThan => "<".to_string(),
1✔
2084
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
1✔
2085
            BinaryOperator::Max => "max".to_string(),
5✔
2086
            BinaryOperator::Min => "min".to_string(),
2✔
2087
            BinaryOperator::Mul => "*".to_string(),
6✔
2088
            BinaryOperator::Remainder => "%".to_string(),
1✔
2089
            BinaryOperator::Step => "step".to_string(),
1✔
2090
            BinaryOperator::Sub => "-".to_string(),
7✔
2091
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
2092
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
2093
            BinaryOperator::Vec2 => "vec2".to_string(),
×
2094
        }
2095
    }
2096
}
2097

2098
/// Ternary operator.
2099
///
2100
/// Operator applied between three operands. The type of the operands and the
2101
/// result are not necessarily the same. Valid operand types depend on the
2102
/// operator itself.
2103
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2104
pub enum TernaryOperator {
2105
    /// Linear blend ("mix") operator.
2106
    ///
2107
    /// Returns the linear blend between the first and second argument, based on
2108
    /// the fraction of the third argument. If the operands are vectors, they
2109
    /// must be of the same rank, and the result is a vector of that rank
2110
    /// and same element scalar type.
2111
    ///
2112
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2113
    /// (1 - t) + y * t`.
2114
    Mix,
2115

2116
    /// Smooth stepping operator.
2117
    ///
2118
    /// Returns the smooth Hermitian interpolation between the first and second
2119
    /// argument, calculated at the third argument. If the operands are vectors,
2120
    /// they must be of the same rank, and the result is a vector of that
2121
    /// rank and same element scalar type.
2122
    ///
2123
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2124
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2125
    /// represents the fractional position of `x` between `low` and `high`.
2126
    ///
2127
    /// The result is always a floating point scalar in \[0:1\].
2128
    SmoothStep,
2129

2130
    /// Constructor for 3-element vectors.
2131
    ///
2132
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2133
    /// consisting of those three elements `(x, y, z)`.
2134
    Vec3,
2135
}
2136

2137
impl ToWgslString for TernaryOperator {
2138
    fn to_wgsl_string(&self) -> String {
3✔
2139
        match *self {
3✔
2140
            TernaryOperator::Mix => "mix".to_string(),
2✔
2141
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
1✔
2142
            TernaryOperator::Vec3 => "vec3".to_string(),
×
2143
        }
2144
    }
2145
}
2146

2147
/// Expression writer.
2148
///
2149
/// Utility to write expressions with a simple functional syntax. Expressions
2150
/// created with the writer are gatherned into a [`Module`] which can be
2151
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2152
///
2153
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2154
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2155
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2156
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2157
/// to assign it to the [`EffectAsset`].
2158
///
2159
/// # Example
2160
///
2161
/// ```
2162
/// # use bevy_hanabi::*;
2163
/// # use bevy::prelude::*;
2164
/// // Create a writer
2165
/// let w = ExprWriter::new();
2166
///
2167
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2168
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2169
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2170
///
2171
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2172
/// let expr: ExprHandle = expr.expr();
2173
///
2174
/// // Create a modifier and assign the expression to one of its input(s)
2175
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2176
///
2177
/// // Create an EffectAsset with the modifier and the Module from the writer
2178
/// let effect =
2179
///     EffectAsset::new(1024, Spawner::rate(32_f32.into()), w.finish()).init(init_modifier);
2180
/// ```
2181
///
2182
/// [`finish()`]: ExprWriter::finish
2183
/// [`EffectAsset`]: crate::EffectAsset
2184
/// [`Modifer`]: crate::Modifier
2185
#[derive(Debug, Default, Clone)]
2186
pub struct ExprWriter {
2187
    module: Rc<RefCell<Module>>,
2188
}
2189

2190
#[allow(dead_code)]
2191
impl ExprWriter {
2192
    /// Create a new writer.
2193
    ///
2194
    /// The writer owns a new [`Module`] internally, and write all expressions
2195
    /// to it. The module can be released to the user with [`finish()`] once
2196
    /// done using the writer.
2197
    ///
2198
    /// [`finish()`]: ExprWriter::finish
2199
    pub fn new() -> Self {
3✔
2200
        Self {
2201
            module: Rc::new(RefCell::new(Module::default())),
3✔
2202
        }
2203
    }
2204

2205
    /// Create a new writer from an existing module.
2206
    ///
2207
    /// This is an advanced use entry point to write expressions into an
2208
    /// existing [`Module`]. In general, users should prefer using
2209
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2210
    /// same [`ExprWriter`] to write all expressions of the same
2211
    /// [`EffectAsset`].
2212
    ///
2213
    /// [`EffectAsset`]: crate::EffectAsset
2214
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2215
        Self { module }
2216
    }
2217

2218
    /// Add a new property.
2219
    ///
2220
    /// See [`Property`] for more details on what effect properties are.
2221
    ///
2222
    /// # Panics
2223
    ///
2224
    /// Panics if a property with the same name already exists.
2225
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2226
        self.module.borrow_mut().add_property(name, default_value)
1✔
2227
    }
2228

2229
    /// Push a new expression into the writer.
2230
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2231
        let expr = {
13✔
2232
            let mut m = self.module.borrow_mut();
13✔
2233
            m.push(expr.into())
13✔
2234
        };
2235
        WriterExpr {
2236
            expr,
2237
            module: Rc::clone(&self.module),
13✔
2238
        }
2239
    }
2240

2241
    /// Create a new writer expression from a literal constant.
2242
    ///
2243
    /// # Example
2244
    ///
2245
    /// ```
2246
    /// # use bevy_hanabi::*;
2247
    /// let mut w = ExprWriter::new();
2248
    /// let x = w.lit(-3.5); // x = -3.5;
2249
    /// ```
2250
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2251
        self.push(Expr::Literal(LiteralExpr {
11✔
2252
            value: value.into(),
11✔
2253
        }))
2254
    }
2255

2256
    /// Create a new writer expression from an attribute.
2257
    ///
2258
    /// # Example
2259
    ///
2260
    /// ```
2261
    /// # use bevy_hanabi::*;
2262
    /// let mut w = ExprWriter::new();
2263
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2264
    /// ```
2265
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2266
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
1✔
2267
    }
2268

2269
    /// Create a new writer expression from an attribute on a parent effect.
2270
    ///
2271
    /// # Example
2272
    ///
2273
    /// ```
2274
    /// # use bevy_hanabi::*;
2275
    /// let mut w = ExprWriter::new();
2276
    /// let x = w.parent_attr(Attribute::POSITION); // x = parent_particle.position;
2277
    /// ```
NEW
2278
    pub fn parent_attr(&self, attr: Attribute) -> WriterExpr {
×
NEW
2279
        self.push(Expr::ParentAttribute(AttributeExpr::new(attr)))
×
2280
    }
2281

2282
    /// Create a new writer expression from a property.
2283
    ///
2284
    /// # Example
2285
    ///
2286
    /// ```
2287
    /// # use bevy_hanabi::*;
2288
    /// let mut w = ExprWriter::new();
2289
    /// let prop = w.add_property("my_prop", 3.0.into());
2290
    /// let x = w.prop(prop); // x = properties.my_prop;
2291
    /// ```
2292
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2293
        self.push(Expr::Property(PropertyExpr::new(handle)))
1✔
2294
    }
2295

2296
    /// Create a new writer expression representing the current simulation time.
2297
    ///
2298
    /// # Example
2299
    ///
2300
    /// ```
2301
    /// # use bevy_hanabi::*;
2302
    /// let mut w = ExprWriter::new();
2303
    /// let x = w.time(); // x = sim_params.time;
2304
    /// ```
2305
    pub fn time(&self) -> WriterExpr {
×
2306
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2307
    }
2308

2309
    /// Create a new writer expression representing the simulation delta time
2310
    /// since last frame.
2311
    ///
2312
    /// # Example
2313
    ///
2314
    /// ```
2315
    /// # use bevy_hanabi::*;
2316
    /// let mut w = ExprWriter::new();
2317
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2318
    /// ```
2319
    pub fn delta_time(&self) -> WriterExpr {
×
2320
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2321
    }
2322

2323
    /// Create a new writer expression representing a random value of the given
2324
    /// type.
2325
    ///
2326
    /// The type can be any scalar or vector type. Matrix types are not
2327
    /// supported. The random values generated are uniformly distributed in
2328
    /// `[0:1]`. For vectors, each component is sampled separately.
2329
    ///
2330
    /// # Panics
2331
    ///
2332
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2333
    ///
2334
    /// # Example
2335
    ///
2336
    /// ```
2337
    /// # use bevy_hanabi::*;
2338
    /// let mut w = ExprWriter::new();
2339
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2340
    /// ```
2341
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2342
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2343
            value_type.into(),
×
2344
        ))))
2345
    }
2346

2347
    /// Create a new writer expression representing the alpha cutoff value used
2348
    /// for alpha masking.
2349
    ///
2350
    /// This expression is only valid when used in the context of the fragment
2351
    /// shader, in the render context.
2352
    ///
2353
    /// # Example
2354
    ///
2355
    /// ```
2356
    /// # use bevy_hanabi::*;
2357
    /// let mut w = ExprWriter::new();
2358
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2359
    /// ```
2360
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2361
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2362
            BuiltInOperator::AlphaCutoff,
×
2363
        )))
2364
    }
2365

2366
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2367
    /// were written by the writer.
2368
    ///
2369
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2370
    /// to that effect the modifiers which use the expressions created by this
2371
    /// writer.
2372
    ///
2373
    /// # Example
2374
    ///
2375
    /// ```
2376
    /// # use bevy_hanabi::*;
2377
    /// # let spawner = Spawner::default();
2378
    /// let mut w = ExprWriter::new();
2379
    /// // [...]
2380
    /// let module = w.finish();
2381
    /// let asset = EffectAsset::new(256, spawner, module);
2382
    /// ```
2383
    ///
2384
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2385
    pub fn finish(self) -> Module {
3✔
2386
        self.module.take()
3✔
2387
    }
2388
}
2389

2390
/// Intermediate expression from an [`ExprWriter`].
2391
///
2392
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2393
/// retains a reference to the underlying [`Module`] and therefore can easily be
2394
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2395
/// being more heavyweight and locking the underlying [`Module`] under a
2396
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2397
/// opposition is a very lightweight type, similar to a simple index. And like
2398
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2399
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2400
///
2401
/// In addition, [`WriterExpr`] implements several numerical operators like the
2402
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2403
/// [`WriterExpr`].
2404
///
2405
/// ```
2406
/// # use bevy_hanabi::*;
2407
/// let mut w = ExprWriter::new();
2408
/// let x = w.lit(-3.5);
2409
/// let y = w.lit(78.);
2410
/// let z = x + y; // == 74.5
2411
/// ```
2412
///
2413
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2414
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2415
///
2416
/// ```
2417
/// # use bevy_hanabi::*;
2418
/// let mut w = ExprWriter::new();
2419
/// let my_prop = w.add_property("my_prop", 3.0.into());
2420
///
2421
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2422
/// let x = (w.lit(-3.5) + w.lit(1.))
2423
///     .max(w.prop(my_prop))
2424
///     .mul(w.lit(0.5))
2425
///     .sub(w.attr(Attribute::POSITION));
2426
///
2427
/// let handle: ExprHandle = x.expr();
2428
/// ```
2429
#[derive(Debug, Clone)]
2430
pub struct WriterExpr {
2431
    expr: ExprHandle,
2432
    module: Rc<RefCell<Module>>,
2433
}
2434

2435
impl WriterExpr {
2436
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2437
        let expr = self.module.borrow_mut().push(Expr::Unary {
1✔
2438
            op,
1✔
2439
            expr: self.expr,
1✔
2440
        });
2441
        WriterExpr {
2442
            expr,
2443
            module: self.module,
1✔
2444
        }
2445
    }
2446

2447
    /// Take the absolute value of the current expression.
2448
    ///
2449
    /// This is a unary operator, which applies component-wise to vector and
2450
    /// matrix operand expressions.
2451
    ///
2452
    /// # Example
2453
    ///
2454
    /// ```
2455
    /// # use bevy_hanabi::*;
2456
    /// # let mut w = ExprWriter::new();
2457
    /// // A literal expression `x = -3.5;`.
2458
    /// let x = w.lit(-3.5);
2459
    ///
2460
    /// // The absolute value `y = abs(x);`.
2461
    /// let y = x.abs(); // == 3.5
2462
    /// ```
2463
    #[inline]
2464
    pub fn abs(self) -> Self {
1✔
2465
        self.unary_op(UnaryOperator::Abs)
1✔
2466
    }
2467

2468
    /// Apply the logical operator "all" to the current bool vector expression.
2469
    ///
2470
    /// This is a unary operator, which applies to vector operand expressions to
2471
    /// produce a scalar boolean.
2472
    ///
2473
    /// # Example
2474
    ///
2475
    /// ```
2476
    /// # use bevy_hanabi::*;
2477
    /// # use bevy::math::BVec3;
2478
    /// # let mut w = ExprWriter::new();
2479
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2480
    /// let x = w.lit(BVec3::new(true, false, true));
2481
    ///
2482
    /// // Check if all components are true `y = all(x);`.
2483
    /// let y = x.all(); // == false
2484
    /// ```
2485
    #[inline]
2486
    pub fn all(self) -> Self {
×
2487
        self.unary_op(UnaryOperator::All)
×
2488
    }
2489

2490
    /// Apply the logical operator "any" to the current bool vector expression.
2491
    ///
2492
    /// This is a unary operator, which applies to vector operand expressions to
2493
    /// produce a scalar boolean.
2494
    ///
2495
    /// # Example
2496
    ///
2497
    /// ```
2498
    /// # use bevy_hanabi::*;
2499
    /// # use bevy::math::BVec3;
2500
    /// # let mut w = ExprWriter::new();
2501
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2502
    /// let x = w.lit(BVec3::new(true, false, true));
2503
    ///
2504
    /// // Check if any components is true `y = any(x);`.
2505
    /// let y = x.any(); // == true
2506
    /// ```
2507
    #[inline]
2508
    pub fn any(self) -> Self {
×
2509
        self.unary_op(UnaryOperator::Any)
×
2510
    }
2511

2512
    /// Apply the "ceil" operator to the current float scalar or vector
2513
    /// expression.
2514
    ///
2515
    /// This is a unary operator, which applies to float scalar or vector
2516
    /// operand expressions to produce a float scalar or vector. It applies
2517
    /// component-wise to vector operand expressions.
2518
    ///
2519
    /// # Example
2520
    ///
2521
    /// ```
2522
    /// # use bevy_hanabi::*;
2523
    /// # use bevy::math::Vec3;
2524
    /// # let mut w = ExprWriter::new();
2525
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2526
    /// let x = w.lit(Vec3::ONE);
2527
    ///
2528
    /// // Ceil: `y = ceil(x);`
2529
    /// let y = x.ceil();
2530
    /// ```
2531
    #[inline]
2532
    pub fn ceil(self) -> Self {
×
2533
        self.unary_op(UnaryOperator::Ceil)
×
2534
    }
2535

2536
    /// Apply the "cos" operator to the current float scalar or vector
2537
    /// expression.
2538
    ///
2539
    /// This is a unary operator, which applies to float scalar or vector
2540
    /// operand expressions to produce a float scalar or vector. It applies
2541
    /// component-wise to vector operand expressions.
2542
    ///
2543
    /// # Example
2544
    ///
2545
    /// ```
2546
    /// # use bevy_hanabi::*;
2547
    /// # use bevy::math::Vec3;
2548
    /// # let mut w = ExprWriter::new();
2549
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2550
    /// let x = w.lit(Vec3::ONE);
2551
    ///
2552
    /// // Cos: `y = cos(x);`
2553
    /// let y = x.cos();
2554
    /// ```
2555
    #[inline]
2556
    pub fn cos(self) -> Self {
×
2557
        self.unary_op(UnaryOperator::Cos)
×
2558
    }
2559

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

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

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

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

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

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

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

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

2752
    /// Apply the "normalize" operator to the current float vector expression.
2753
    ///
2754
    /// This is a unary operator, which applies to float vector operand
2755
    /// expressions to produce another float vector with unit length
2756
    /// (normalized).
2757
    ///
2758
    /// # Example
2759
    ///
2760
    /// ```
2761
    /// # use bevy_hanabi::*;
2762
    /// # use bevy::math::Vec3;
2763
    /// # let mut w = ExprWriter::new();
2764
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2765
    /// let x = w.lit(Vec3::ONE);
2766
    ///
2767
    /// // Normalize: `y = normalize(x);`
2768
    /// let y = x.normalized();
2769
    /// ```
2770
    #[inline]
2771
    pub fn normalized(self) -> Self {
×
2772
        self.unary_op(UnaryOperator::Normalize)
×
2773
    }
2774

2775
    /// Apply the "pack4x8snorm" operator to the current 4-component float
2776
    /// vector expression.
2777
    ///
2778
    /// This is a unary operator, which applies to 4-component float vector
2779
    /// operand expressions to produce a single `u32` scalar expression.
2780
    ///
2781
    /// # Example
2782
    ///
2783
    /// ```
2784
    /// # use bevy_hanabi::*;
2785
    /// # use bevy::math::Vec4;
2786
    /// # let mut w = ExprWriter::new();
2787
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2788
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2789
    ///
2790
    /// // Pack: `y = pack4x8snorm(x);`
2791
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
2792
    /// ```
2793
    #[inline]
2794
    pub fn pack4x8snorm(self) -> Self {
×
2795
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
2796
    }
2797

2798
    /// Apply the "pack4x8unorm" operator to the current 4-component float
2799
    /// vector expression.
2800
    ///
2801
    /// This is a unary operator, which applies to 4-component float vector
2802
    /// operand expressions to produce a single `u32` scalar expression.
2803
    ///
2804
    /// # Example
2805
    ///
2806
    /// ```
2807
    /// # use bevy_hanabi::*;
2808
    /// # use bevy::math::Vec4;
2809
    /// # let mut w = ExprWriter::new();
2810
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2811
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2812
    ///
2813
    /// // Pack: `y = pack4x8unorm(x);`
2814
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
2815
    /// ```
2816
    #[inline]
2817
    pub fn pack4x8unorm(self) -> Self {
×
2818
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
2819
    }
2820

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

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

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

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

2917
    /// Apply the "unpack4x8snorm" operator to the current `u32` scalar
2918
    /// expression.
2919
    ///
2920
    /// This is a unary operator, which applies to `u32` scalar operand
2921
    /// expressions to produce a 4-component floating point vector of signed
2922
    /// normalized components in `[-1:1]`.
2923
    ///
2924
    /// # Example
2925
    ///
2926
    /// ```
2927
    /// # use bevy_hanabi::*;
2928
    /// # use bevy::math::Vec3;
2929
    /// # let mut w = ExprWriter::new();
2930
    /// // A literal expression `y = 0x7F007FFFu32;`.
2931
    /// let y = w.lit(0x7F007FFFu32);
2932
    ///
2933
    /// // Unpack: `x = unpack4x8snorm(y);`
2934
    /// let x = y.unpack4x8snorm(); // vec4<f32>(-1., 1., 0., 7.2)
2935
    /// ```
2936
    #[inline]
2937
    pub fn unpack4x8snorm(self) -> Self {
×
2938
        self.unary_op(UnaryOperator::Unpack4x8snorm)
×
2939
    }
2940

2941
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
2942
    /// expression.
2943
    ///
2944
    /// This is a unary operator, which applies to `u32` scalar operand
2945
    /// expressions to produce a 4-component floating point vector of unsigned
2946
    /// normalized components in `[0:1]`.
2947
    ///
2948
    /// # Example
2949
    ///
2950
    /// ```
2951
    /// # use bevy_hanabi::*;
2952
    /// # use bevy::math::Vec3;
2953
    /// # let mut w = ExprWriter::new();
2954
    /// // A literal expression `y = 0xFF00FF00u32;`.
2955
    /// let y = w.lit(0xFF00FF00u32);
2956
    ///
2957
    /// // Unpack: `x = unpack4x8unorm(y);`
2958
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
2959
    /// ```
2960
    #[inline]
2961
    pub fn unpack4x8unorm(self) -> Self {
×
2962
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
2963
    }
2964

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

2989
    /// Get the first component of a scalar or vector.
2990
    ///
2991
    /// # Example
2992
    ///
2993
    /// ```
2994
    /// # use bevy_hanabi::*;
2995
    /// # use bevy::math::Vec3;
2996
    /// # let mut w = ExprWriter::new();
2997
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2998
    /// let v = w.lit(Vec3::ONE);
2999
    ///
3000
    /// // f = v.x;`
3001
    /// let f = v.x();
3002
    /// ```
3003
    #[inline]
3004
    pub fn x(self) -> Self {
×
3005
        self.unary_op(UnaryOperator::X)
×
3006
    }
3007

3008
    /// Get the second component of a vector.
3009
    ///
3010
    /// # Example
3011
    ///
3012
    /// ```
3013
    /// # use bevy_hanabi::*;
3014
    /// # use bevy::math::Vec3;
3015
    /// # let mut w = ExprWriter::new();
3016
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3017
    /// let v = w.lit(Vec3::ONE);
3018
    ///
3019
    /// // f = v.y;`
3020
    /// let f = v.y();
3021
    /// ```
3022
    #[inline]
3023
    pub fn y(self) -> Self {
×
3024
        self.unary_op(UnaryOperator::Y)
×
3025
    }
3026

3027
    /// Get the third component of a vector.
3028
    ///
3029
    /// # Example
3030
    ///
3031
    /// ```
3032
    /// # use bevy_hanabi::*;
3033
    /// # use bevy::math::Vec3;
3034
    /// # let mut w = ExprWriter::new();
3035
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3036
    /// let v = w.lit(Vec3::ONE);
3037
    ///
3038
    /// // f = v.z;`
3039
    /// let f = v.z();
3040
    /// ```
3041
    #[inline]
3042
    pub fn z(self) -> Self {
×
3043
        self.unary_op(UnaryOperator::Z)
×
3044
    }
3045

3046
    /// Get the fourth component of a vector.
3047
    ///
3048
    /// # Example
3049
    ///
3050
    /// ```
3051
    /// # use bevy_hanabi::*;
3052
    /// # use bevy::math::Vec3;
3053
    /// # let mut w = ExprWriter::new();
3054
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
3055
    /// let v = w.lit(Vec3::ONE);
3056
    ///
3057
    /// // f = v.w;`
3058
    /// let f = v.w();
3059
    /// ```
3060
    #[inline]
3061
    pub fn w(self) -> Self {
×
3062
        self.unary_op(UnaryOperator::W)
×
3063
    }
3064

3065
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
3066
        assert_eq!(self.module, other.module);
5✔
3067
        let left = self.expr;
5✔
3068
        let right = other.expr;
5✔
3069
        let expr = self
5✔
3070
            .module
5✔
3071
            .borrow_mut()
3072
            .push(Expr::Binary { op, left, right });
5✔
3073
        WriterExpr {
3074
            expr,
3075
            module: self.module,
5✔
3076
        }
3077
    }
3078

3079
    /// Add the current expression with another expression.
3080
    ///
3081
    /// This is a binary operator, which applies component-wise to vector
3082
    /// operand expressions.
3083
    ///
3084
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3085
    /// symbol, as an alternative to calling this method directly.
3086
    ///
3087
    /// # Example
3088
    ///
3089
    /// ```
3090
    /// # use bevy_hanabi::*;
3091
    /// # use bevy::math::Vec2;
3092
    /// # let mut w = ExprWriter::new();
3093
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3094
    /// let x = w.lit(Vec2::new(3., -2.));
3095
    ///
3096
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3097
    /// let y = w.lit(Vec2::new(1., 5.));
3098
    ///
3099
    /// // The sum of both vectors `z = x + y;`.
3100
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3101
    ///                   // -OR-
3102
    ///                   // let z = x + y;
3103
    /// ```
3104
    #[allow(clippy::should_implement_trait)]
3105
    #[inline]
3106
    pub fn add(self, other: Self) -> Self {
2✔
3107
        self.binary_op(other, BinaryOperator::Add)
2✔
3108
    }
3109

3110
    /// Calculate the cross product of the current expression by another
3111
    /// expression.
3112
    ///
3113
    /// This is a binary operator, which applies to vector operands of size 3
3114
    /// only, and always produces a vector of the same size.
3115
    ///
3116
    /// # Example
3117
    ///
3118
    /// ```
3119
    /// # use bevy_hanabi::*;
3120
    /// # use bevy::math::Vec3;
3121
    /// # let mut w = ExprWriter::new();
3122
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3123
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3124
    ///
3125
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3126
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3127
    ///
3128
    /// // The cross product of both vectors `z = cross(x, y);`.
3129
    /// let z = x.cross(y);
3130
    /// ```
3131
    #[inline]
3132
    pub fn cross(self, other: Self) -> Self {
×
3133
        self.binary_op(other, BinaryOperator::Cross)
×
3134
    }
3135

3136
    /// Calculate the dot product of the current expression by another
3137
    /// expression.
3138
    ///
3139
    /// This is a binary operator, which applies to vector operands of same size
3140
    /// only, and always produces a floating point scalar.
3141
    ///
3142
    /// # Example
3143
    ///
3144
    /// ```
3145
    /// # use bevy_hanabi::*;
3146
    /// # use bevy::math::Vec2;
3147
    /// # let mut w = ExprWriter::new();
3148
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3149
    /// let x = w.lit(Vec2::new(3., -2.));
3150
    ///
3151
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3152
    /// let y = w.lit(Vec2::new(1., 5.));
3153
    ///
3154
    /// // The dot product of both vectors `z = dot(x, y);`.
3155
    /// let z = x.dot(y);
3156
    /// ```
3157
    #[inline]
3158
    pub fn dot(self, other: Self) -> Self {
×
3159
        self.binary_op(other, BinaryOperator::Dot)
×
3160
    }
3161

3162
    /// Calculate the distance between the current expression and another
3163
    /// expression.
3164
    ///
3165
    /// This is a binary operator.
3166
    ///
3167
    /// # Example
3168
    ///
3169
    /// ```
3170
    /// # use bevy_hanabi::*;
3171
    /// # use bevy::math::Vec3;
3172
    /// # let mut w = ExprWriter::new();
3173
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3174
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3175
    ///
3176
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3177
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3178
    ///
3179
    /// // The distance between the vectors `z = distance(x, y);`.
3180
    /// let z = x.distance(y);
3181
    /// ```
3182
    #[inline]
3183
    pub fn distance(self, other: Self) -> Self {
×
3184
        self.binary_op(other, BinaryOperator::Distance)
×
3185
    }
3186

3187
    /// Divide the current expression by another expression.
3188
    ///
3189
    /// This is a binary operator, which applies component-wise to vector
3190
    /// operand expressions.
3191
    ///
3192
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3193
    /// symbol, as an alternative to calling this method directly.
3194
    ///
3195
    /// # Example
3196
    ///
3197
    /// ```
3198
    /// # use bevy_hanabi::*;
3199
    /// # use bevy::math::Vec2;
3200
    /// # let mut w = ExprWriter::new();
3201
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3202
    /// let x = w.lit(Vec2::new(3., -2.));
3203
    ///
3204
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3205
    /// let y = w.lit(Vec2::new(1., 5.));
3206
    ///
3207
    /// // The quotient of both vectors `z = x / y;`.
3208
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3209
    ///                   // -OR-
3210
    ///                   // let z = x / y;
3211
    /// ```
3212
    #[allow(clippy::should_implement_trait)]
3213
    #[inline]
3214
    pub fn div(self, other: Self) -> Self {
×
3215
        self.binary_op(other, BinaryOperator::Div)
×
3216
    }
3217

3218
    /// Apply the logical operator "greater than or equal" to this expression
3219
    /// and another expression.
3220
    ///
3221
    /// This is a binary operator, which applies component-wise to vector
3222
    /// operand expressions.
3223
    ///
3224
    /// # Example
3225
    ///
3226
    /// ```
3227
    /// # use bevy_hanabi::*;
3228
    /// # use bevy::math::Vec3;
3229
    /// # let mut w = ExprWriter::new();
3230
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3231
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3232
    ///
3233
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3234
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3235
    ///
3236
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3237
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3238
    /// ```
3239
    #[inline]
3240
    pub fn ge(self, other: Self) -> Self {
×
3241
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3242
    }
3243

3244
    /// Apply the logical operator "greater than" to this expression and another
3245
    /// expression.
3246
    ///
3247
    /// This is a binary operator, which applies component-wise to vector
3248
    /// operand expressions.
3249
    ///
3250
    /// # Example
3251
    ///
3252
    /// ```
3253
    /// # use bevy_hanabi::*;
3254
    /// # use bevy::math::Vec3;
3255
    /// # let mut w = ExprWriter::new();
3256
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3257
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3258
    ///
3259
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3260
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3261
    ///
3262
    /// // The boolean result of the greater than operation `z = (x > y);`.
3263
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3264
    /// ```
3265
    #[inline]
3266
    pub fn gt(self, other: Self) -> Self {
×
3267
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3268
    }
3269

3270
    /// Apply the logical operator "less than or equal" to this expression and
3271
    /// another expression.
3272
    ///
3273
    /// This is a binary operator, which applies component-wise to vector
3274
    /// operand expressions.
3275
    ///
3276
    /// # Example
3277
    ///
3278
    /// ```
3279
    /// # use bevy_hanabi::*;
3280
    /// # use bevy::math::Vec3;
3281
    /// # let mut w = ExprWriter::new();
3282
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3283
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3284
    ///
3285
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3286
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3287
    ///
3288
    /// // The boolean result of the less than or equal operation `z = (x <= y);`.
3289
    /// let z = x.le(y); // == vec3<bool>(false, true, true)
3290
    /// ```
3291
    #[inline]
3292
    pub fn le(self, other: Self) -> Self {
×
3293
        self.binary_op(other, BinaryOperator::LessThanOrEqual)
×
3294
    }
3295

3296
    /// Apply the logical operator "less than" to this expression and another
3297
    /// expression.
3298
    ///
3299
    /// This is a binary operator, which applies component-wise to vector
3300
    /// operand expressions.
3301
    ///
3302
    /// # Example
3303
    ///
3304
    /// ```
3305
    /// # use bevy_hanabi::*;
3306
    /// # use bevy::math::Vec3;
3307
    /// # let mut w = ExprWriter::new();
3308
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3309
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3310
    ///
3311
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3312
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3313
    ///
3314
    /// // The boolean result of the less than operation `z = (x < y);`.
3315
    /// let z = x.lt(y); // == vec3<bool>(false, true, false)
3316
    /// ```
3317
    #[inline]
3318
    pub fn lt(self, other: Self) -> Self {
×
3319
        self.binary_op(other, BinaryOperator::LessThan)
×
3320
    }
3321

3322
    /// Take the maximum value of the current expression and another expression.
3323
    ///
3324
    /// This is a binary operator, which applies component-wise to vector
3325
    /// operand expressions.
3326
    ///
3327
    /// # Example
3328
    ///
3329
    /// ```
3330
    /// # use bevy_hanabi::*;
3331
    /// # use bevy::math::Vec2;
3332
    /// # let mut w = ExprWriter::new();
3333
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3334
    /// let x = w.lit(Vec2::new(3., -2.));
3335
    ///
3336
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3337
    /// let y = w.lit(Vec2::new(1., 5.));
3338
    ///
3339
    /// // The maximum of both vectors `z = max(x, y);`.
3340
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3341
    /// ```
3342
    #[inline]
3343
    pub fn max(self, other: Self) -> Self {
1✔
3344
        self.binary_op(other, BinaryOperator::Max)
1✔
3345
    }
3346

3347
    /// Take the minimum value of the current expression and another expression.
3348
    ///
3349
    /// This is a binary operator, which applies component-wise to vector
3350
    /// operand expressions.
3351
    ///
3352
    /// # Example
3353
    ///
3354
    /// ```
3355
    /// # use bevy_hanabi::*;
3356
    /// # use bevy::math::Vec2;
3357
    /// # let mut w = ExprWriter::new();
3358
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3359
    /// let x = w.lit(Vec2::new(3., -2.));
3360
    ///
3361
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3362
    /// let y = w.lit(Vec2::new(1., 5.));
3363
    ///
3364
    /// // The minimum of both vectors `z = min(x, y);`.
3365
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3366
    /// ```
3367
    #[inline]
3368
    pub fn min(self, other: Self) -> Self {
1✔
3369
        self.binary_op(other, BinaryOperator::Min)
1✔
3370
    }
3371

3372
    /// Multiply the current expression with another expression.
3373
    ///
3374
    /// This is a binary operator, which applies component-wise to vector
3375
    /// operand expressions.
3376
    ///
3377
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3378
    /// symbol, as an alternative to calling this method directly.
3379
    ///
3380
    /// # Example
3381
    ///
3382
    /// ```
3383
    /// # use bevy_hanabi::*;
3384
    /// # use bevy::math::Vec2;
3385
    /// # let mut w = ExprWriter::new();
3386
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3387
    /// let x = w.lit(Vec2::new(3., -2.));
3388
    ///
3389
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3390
    /// let y = w.lit(Vec2::new(1., 5.));
3391
    ///
3392
    /// // The product of both vectors `z = x * y;`.
3393
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3394
    ///                   // -OR-
3395
    ///                   // let z = x * y;
3396
    /// ```
3397
    #[allow(clippy::should_implement_trait)]
3398
    #[inline]
3399
    pub fn mul(self, other: Self) -> Self {
1✔
3400
        self.binary_op(other, BinaryOperator::Mul)
1✔
3401
    }
3402

3403
    /// Calculate the remainder of the division of the current expression by
3404
    /// another expression.
3405
    ///
3406
    /// This is a binary operator.
3407
    ///
3408
    /// # Example
3409
    ///
3410
    /// ```
3411
    /// # use bevy_hanabi::*;
3412
    /// # use bevy::math::Vec3;
3413
    /// # let mut w = ExprWriter::new();
3414
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3415
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3416
    ///
3417
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3418
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3419
    ///
3420
    /// // The remainder of the division `z = x % y;`.
3421
    /// let z = x.rem(y);
3422
    /// ```
3423
    #[allow(clippy::should_implement_trait)]
3424
    #[inline]
3425
    pub fn rem(self, other: Self) -> Self {
×
3426
        self.binary_op(other, BinaryOperator::Remainder)
×
3427
    }
3428

3429
    /// Calculate the step of a value with respect to a reference.
3430
    ///
3431
    /// This is a binary operator, which applies component-wise to vector
3432
    /// operand expressions.
3433
    ///
3434
    /// # Example
3435
    ///
3436
    /// ```
3437
    /// # use bevy_hanabi::*;
3438
    /// # use bevy::math::Vec3;
3439
    /// # let mut w = ExprWriter::new();
3440
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3441
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3442
    ///
3443
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3444
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3445
    ///
3446
    /// // The step value
3447
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3448
    /// ```
3449
    #[allow(clippy::should_implement_trait)]
3450
    #[inline]
3451
    pub fn step(self, edge: Self) -> Self {
×
3452
        // Note: order is step(edge, x) but x.step(edge)
3453
        edge.binary_op(self, BinaryOperator::Step)
×
3454
    }
3455

3456
    /// Subtract another expression from the current expression.
3457
    ///
3458
    /// This is a binary operator, which applies component-wise to vector
3459
    /// operand expressions.
3460
    ///
3461
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3462
    /// symbol, as an alternative to calling this method directly.
3463
    ///
3464
    /// # Example
3465
    ///
3466
    /// ```
3467
    /// # use bevy_hanabi::*;
3468
    /// # use bevy::math::Vec2;
3469
    /// # let mut w = ExprWriter::new();
3470
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3471
    /// let x = w.lit(Vec2::new(3., -2.));
3472
    ///
3473
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3474
    /// let y = w.lit(Vec2::new(1., 5.));
3475
    ///
3476
    /// // The difference of both vectors `z = x - y;`.
3477
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3478
    ///                   // -OR-
3479
    ///                   // let z = x - y;
3480
    /// ```
3481
    #[allow(clippy::should_implement_trait)]
3482
    #[inline]
3483
    pub fn sub(self, other: Self) -> Self {
×
3484
        self.binary_op(other, BinaryOperator::Sub)
×
3485
    }
3486

3487
    /// Apply the logical operator "uniform" to this expression and another
3488
    /// expression.
3489
    ///
3490
    /// This is a binary operator, which applies component-wise to vector
3491
    /// operand expressions. That is, for vectors, this produces a vector of
3492
    /// random values where each component is uniformly distributed within the
3493
    /// bounds of the related component of both operands.
3494
    ///
3495
    /// # Example
3496
    ///
3497
    /// ```
3498
    /// # use bevy_hanabi::*;
3499
    /// # use bevy::math::Vec3;
3500
    /// # let mut w = ExprWriter::new();
3501
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3502
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3503
    ///
3504
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3505
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3506
    ///
3507
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3508
    /// let z = x.uniform(y);
3509
    /// ```
3510
    #[inline]
3511
    pub fn uniform(self, other: Self) -> Self {
×
3512
        self.binary_op(other, BinaryOperator::UniformRand)
×
3513
    }
3514

3515
    /// Apply the logical operator "normal" to this expression and another
3516
    /// expression.
3517
    ///
3518
    /// This is a binary operator, which applies component-wise to vector
3519
    /// operand expressions. That is, for vectors, this produces a vector of
3520
    /// random values where each component is normally distributed with a mean
3521
    /// of the corresponding component of the first operand and a standard
3522
    /// deviation of the corresponding component of the second operand.
3523
    ///
3524
    /// # Example
3525
    ///
3526
    /// ```
3527
    /// # use bevy_hanabi::*;
3528
    /// # use bevy::math::Vec3;
3529
    /// # let mut w = ExprWriter::new();
3530
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3531
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3532
    ///
3533
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3534
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3535
    ///
3536
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3537
    /// let z = x.normal(y);
3538
    /// ```
3539
    #[inline]
3540
    pub fn normal(self, other: Self) -> Self {
×
3541
        self.binary_op(other, BinaryOperator::NormalRand)
×
3542
    }
3543

3544
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3545
        assert_eq!(self.module, second.module);
×
3546
        assert_eq!(self.module, third.module);
×
3547
        let first = self.expr;
×
3548
        let second = second.expr;
×
3549
        let third = third.expr;
×
3550
        let expr = self.module.borrow_mut().push(Expr::Ternary {
×
3551
            op,
×
3552
            first,
×
3553
            second,
×
3554
            third,
×
3555
        });
3556
        WriterExpr {
3557
            expr,
3558
            module: self.module,
×
3559
        }
3560
    }
3561

3562
    /// Blending linearly ("mix") two expressions with the fraction provided by
3563
    /// a third expression.
3564
    ///
3565
    /// This is a ternary operator, which applies component-wise to vector
3566
    /// operand expressions.
3567
    ///
3568
    /// # Example
3569
    ///
3570
    /// ```
3571
    /// # use bevy_hanabi::*;
3572
    /// # use bevy::math::Vec2;
3573
    /// # let mut w = ExprWriter::new();
3574
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3575
    /// let x = w.lit(Vec2::new(3., -2.));
3576
    ///
3577
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3578
    /// let y = w.lit(Vec2::new(1., 4.));
3579
    ///
3580
    /// // A fraction `t = 0.5;`.
3581
    /// let t = w.lit(0.25);
3582
    ///
3583
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3584
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3585
    /// ```
3586
    #[inline]
3587
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3588
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3589
    }
3590

3591
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3592
    /// value taken between the given bounds.
3593
    ///
3594
    /// This is a ternary operator, which applies component-wise to vector
3595
    /// operand expressions.
3596
    ///
3597
    /// # Example
3598
    ///
3599
    /// ```
3600
    /// # use bevy_hanabi::*;
3601
    /// # use bevy::math::Vec2;
3602
    /// # let mut w = ExprWriter::new();
3603
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3604
    /// let low = w.lit(Vec2::new(3., -2.));
3605
    ///
3606
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3607
    /// let high = w.lit(Vec2::new(1., 4.));
3608
    ///
3609
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3610
    /// let x = w.lit(Vec2::new(2., 1.));
3611
    ///
3612
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3613
    /// let t = x.smoothstep(low, high); // == 0.5
3614
    /// ```
3615
    #[inline]
3616
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3617
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3618
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3619
    }
3620

3621
    /// Construct a `Vec2` from two scalars.
3622
    ///
3623
    /// # Example
3624
    ///
3625
    /// ```
3626
    /// # use bevy_hanabi::*;
3627
    /// # let mut w = ExprWriter::new();
3628
    /// let theta = w.add_property("theta", 0.0.into());
3629
    /// // Convert the angular property `theta` to a 2D vector.
3630
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3631
    /// let circle_pos = cos_theta.vec2(sin_theta);
3632
    /// ```
3633
    #[inline]
3634
    pub fn vec2(self, y: Self) -> Self {
×
3635
        self.binary_op(y, BinaryOperator::Vec2)
×
3636
    }
3637

3638
    /// Construct a `Vec3` from two scalars.
3639
    ///
3640
    /// # Example
3641
    ///
3642
    /// ```
3643
    /// # use bevy_hanabi::*;
3644
    /// # let mut w = ExprWriter::new();
3645
    /// let theta = w.add_property("theta", 0.0.into());
3646
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
3647
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3648
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
3649
    /// ```
3650
    #[inline]
3651
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
3652
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
3653
    }
3654

3655
    /// Cast an expression to a different type.
3656
    ///
3657
    /// # Example
3658
    ///
3659
    /// ```
3660
    /// # use bevy_hanabi::*;
3661
    /// # use bevy::math::Vec2;
3662
    /// # let mut w = ExprWriter::new();
3663
    /// let x = w.lit(Vec2::new(3., -2.));
3664
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
3665
    /// ```
3666
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
3667
        let target = target.into();
×
3668
        let expr = self
×
3669
            .module
×
3670
            .borrow_mut()
3671
            .push(Expr::Cast(CastExpr::new(self.expr, target)));
×
3672
        WriterExpr {
3673
            expr,
3674
            module: self.module,
×
3675
        }
3676
    }
3677

3678
    /// Finalize an expression chain and return the accumulated expression.
3679
    ///
3680
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
3681
    /// this intermediate expression was built from.
3682
    ///
3683
    /// # Example
3684
    ///
3685
    /// ```
3686
    /// # use bevy_hanabi::*;
3687
    /// # let mut w = ExprWriter::new();
3688
    /// // A literal expression `x = -3.5;`.
3689
    /// let x = w.lit(-3.5);
3690
    ///
3691
    /// // Retrieve the ExprHandle for that expression.
3692
    /// let handle = x.expr();
3693
    /// ```
3694
    #[inline]
3695
    pub fn expr(self) -> ExprHandle {
8✔
3696
        self.expr
8✔
3697
    }
3698
}
3699

3700
impl std::ops::Add<WriterExpr> for WriterExpr {
3701
    type Output = WriterExpr;
3702

3703
    #[inline]
3704
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
3705
        self.add(rhs)
2✔
3706
    }
3707
}
3708

3709
impl std::ops::Sub<WriterExpr> for WriterExpr {
3710
    type Output = WriterExpr;
3711

3712
    #[inline]
3713
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
3714
        self.sub(rhs)
×
3715
    }
3716
}
3717

3718
impl std::ops::Mul<WriterExpr> for WriterExpr {
3719
    type Output = WriterExpr;
3720

3721
    #[inline]
3722
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
3723
        self.mul(rhs)
1✔
3724
    }
3725
}
3726

3727
impl std::ops::Div<WriterExpr> for WriterExpr {
3728
    type Output = WriterExpr;
3729

3730
    #[inline]
3731
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
3732
        self.div(rhs)
×
3733
    }
3734
}
3735

3736
impl std::ops::Rem<WriterExpr> for WriterExpr {
3737
    type Output = WriterExpr;
3738

3739
    #[inline]
3740
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
3741
        self.rem(rhs)
×
3742
    }
3743
}
3744

3745
#[cfg(test)]
3746
mod tests {
3747
    use bevy::{prelude::*, utils::HashSet};
3748

3749
    use super::*;
3750
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
3751

3752
    #[test]
3753
    fn module() {
3754
        let mut m = Module::default();
3755

3756
        #[allow(unsafe_code)]
3757
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
3758
        assert!(m.get(unknown).is_none());
3759
        assert!(m.get_mut(unknown).is_none());
3760
        assert!(matches!(
3761
            m.try_get(unknown),
3762
            Err(ExprError::InvalidExprHandleError(_))
3763
        ));
3764
        assert!(matches!(
3765
            m.try_get_mut(unknown),
3766
            Err(ExprError::InvalidExprHandleError(_))
3767
        ));
3768

3769
        let x = m.lit(5.);
3770
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
3771
        assert_eq!(m.get(x), Some(&expected));
3772
        assert_eq!(m.get_mut(x), Some(&mut expected));
3773
        assert_eq!(m.try_get(x), Ok(&expected));
3774
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
3775
    }
3776

3777
    #[test]
3778
    fn local_var() {
3779
        let property_layout = PropertyLayout::default();
3780
        let particle_layout = ParticleLayout::default();
3781
        let mut ctx =
3782
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3783
        let mut h = HashSet::new();
3784
        for _ in 0..100 {
3785
            let v = ctx.make_local_var();
3786
            assert!(h.insert(v));
3787
        }
3788
    }
3789

3790
    #[test]
3791
    fn make_fn() {
3792
        let property_layout = PropertyLayout::default();
3793
        let particle_layout = ParticleLayout::default();
3794
        let mut ctx =
3795
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3796
        let mut module = Module::default();
3797

3798
        // Make a function
3799
        let func_name = "my_func";
3800
        let args = "arg0: i32, arg1: f32";
3801
        assert!(ctx
3802
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
3803
                m.lit(3.);
3804
                let v = ctx.make_local_var();
3805
                assert_eq!(v, "var0");
3806
                let code = String::new();
3807
                Ok(code)
3808
            })
3809
            .is_ok());
3810

3811
        // The local function context doesn't influence the outer caller context
3812
        let v = ctx.make_local_var();
3813
        assert_eq!(v, "var0");
3814

3815
        // However the module is common to the outer caller and the function
3816
        assert!(!module.expressions.is_empty());
3817
    }
3818

3819
    #[test]
3820
    fn property() {
3821
        let mut m = Module::default();
3822

3823
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
3824
        let _other_prop = m.add_property(
3825
            "other_prop",
3826
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
3827
        );
3828

3829
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
3830
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
3831
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
3832
    }
3833

3834
    #[test]
3835
    fn writer() {
3836
        // Get a module and its writer
3837
        let w = ExprWriter::new();
3838
        let my_prop = w.add_property("my_prop", 3.0.into());
3839

3840
        // Build some expression
3841
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
3842
            + w.lit(-4.).min(w.prop(my_prop));
3843
        let x = x.expr();
3844

3845
        // Create an evaluation context
3846
        let property_layout =
3847
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
3848
        let particle_layout = ParticleLayout::default();
3849
        let m = w.finish();
3850
        let mut context =
3851
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3852

3853
        // Evaluate the expression
3854
        let x = m.try_get(x).unwrap();
3855
        let s = x.eval(&m, &mut context).unwrap();
3856
        assert_eq!(
3857
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties.my_prop))"
3858
                .to_string(),
3859
            s
3860
        );
3861
    }
3862

3863
    #[test]
3864
    fn type_error() {
3865
        let l = Value::Scalar(3.5_f32.into());
3866
        let r: Result<Vec2, ExprError> = l.try_into();
3867
        assert!(r.is_err());
3868
        assert!(matches!(r, Err(ExprError::TypeError(_))));
3869
    }
3870

3871
    #[test]
3872
    fn math_expr() {
3873
        let mut m = Module::default();
3874

3875
        let x = m.attr(Attribute::POSITION);
3876
        let y = m.lit(Vec3::ONE);
3877

3878
        let add = m.add(x, y);
3879
        let sub = m.sub(x, y);
3880
        let mul = m.mul(x, y);
3881
        let div = m.div(x, y);
3882
        let rem = m.rem(x, y);
3883
        let lt = m.lt(x, y);
3884
        let le = m.le(x, y);
3885
        let gt = m.gt(x, y);
3886
        let ge = m.ge(x, y);
3887

3888
        let property_layout = PropertyLayout::default();
3889
        let particle_layout = ParticleLayout::default();
3890
        let mut ctx =
3891
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3892

3893
        for (expr, op) in [
3894
            (add, "+"),
3895
            (sub, "-"),
3896
            (mul, "*"),
3897
            (div, "/"),
3898
            (rem, "%"),
3899
            (lt, "<"),
3900
            (le, "<="),
3901
            (gt, ">"),
3902
            (ge, ">="),
3903
        ] {
3904
            let expr = ctx.eval(&m, expr);
3905
            assert!(expr.is_ok());
3906
            let expr = expr.unwrap();
3907
            assert_eq!(
3908
                expr,
3909
                format!(
3910
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
3911
                    Attribute::POSITION.name(),
3912
                    op,
3913
                )
3914
            );
3915
        }
3916
    }
3917

3918
    #[test]
3919
    fn builtin_expr() {
3920
        let mut m = Module::default();
3921

3922
        // Simulation parameters
3923
        for op in [
3924
            BuiltInOperator::Time,
3925
            BuiltInOperator::DeltaTime,
3926
            BuiltInOperator::VirtualTime,
3927
            BuiltInOperator::VirtualDeltaTime,
3928
            BuiltInOperator::RealTime,
3929
            BuiltInOperator::RealDeltaTime,
3930
        ] {
3931
            let value = m.builtin(op);
3932

3933
            let property_layout = PropertyLayout::default();
3934
            let particle_layout = ParticleLayout::default();
3935
            let mut ctx =
3936
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3937

3938
            let expr = ctx.eval(&m, value);
3939
            assert!(expr.is_ok());
3940
            let expr = expr.unwrap();
3941
            assert_eq!(expr, format!("sim_params.{}", op.name()));
3942
        }
3943

3944
        // is_alive
3945
        {
3946
            let value = m.builtin(BuiltInOperator::IsAlive);
3947

3948
            let property_layout = PropertyLayout::default();
3949
            let particle_layout = ParticleLayout::default();
3950
            let mut ctx =
3951
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3952

3953
            let expr = ctx.eval(&m, value);
3954
            assert!(expr.is_ok());
3955
            let expr = expr.unwrap();
3956
            assert_eq!(expr, "is_alive");
3957
        }
3958

3959
        // BuiltInOperator::Rand (which has side effect)
3960
        for (scalar_type, prefix) in [
3961
            (ScalarType::Bool, "b"),
3962
            (ScalarType::Float, "f"),
3963
            (ScalarType::Int, "i"),
3964
            (ScalarType::Uint, "u"),
3965
        ] {
3966
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
3967

3968
            // Scalar form
3969
            {
3970
                let property_layout = PropertyLayout::default();
3971
                let particle_layout = ParticleLayout::default();
3972
                let mut ctx =
3973
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3974

3975
                let expr = ctx.eval(&m, value);
3976
                assert!(expr.is_ok());
3977
                let expr = expr.unwrap();
3978
                assert_eq!(expr, "var0");
3979
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
3980
            }
3981

3982
            // Vector form
3983
            for count in 2..=4 {
3984
                let vec = m.builtin(BuiltInOperator::Rand(
3985
                    VectorType::new(scalar_type, count).into(),
3986
                ));
3987

3988
                let property_layout = PropertyLayout::default();
3989
                let particle_layout = ParticleLayout::default();
3990
                let mut ctx =
3991
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3992

3993
                let expr = ctx.eval(&m, vec);
3994
                assert!(expr.is_ok());
3995
                let expr = expr.unwrap();
3996
                assert_eq!(expr, "var0");
3997
                assert_eq!(
3998
                    ctx.main_code,
3999
                    format!("let var0 = {}rand{}();\n", prefix, count)
4000
                );
4001
            }
4002
        }
4003
    }
4004

4005
    #[test]
4006
    fn unary_expr() {
4007
        let mut m = Module::default();
4008

4009
        let x = m.attr(Attribute::POSITION);
4010
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
4011
        let z = m.lit(BVec3::new(false, true, false));
4012
        let w = m.lit(Vec4::W);
4013
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
4014
        let us = m.lit(0x0u32);
4015
        let uu = m.lit(0x0u32);
4016

4017
        let abs = m.abs(x);
4018
        let all = m.all(z);
4019
        let any = m.any(z);
4020
        let ceil = m.ceil(y);
4021
        let cos = m.cos(y);
4022
        let exp = m.exp(y);
4023
        let exp2 = m.exp2(y);
4024
        let floor = m.floor(y);
4025
        let fract = m.fract(y);
4026
        let inv_sqrt = m.inverse_sqrt(y);
4027
        let length = m.length(y);
4028
        let log = m.log(y);
4029
        let log2 = m.log2(y);
4030
        let norm = m.normalize(y);
4031
        let pack4x8snorm = m.pack4x8snorm(v);
4032
        let pack4x8unorm = m.pack4x8unorm(v);
4033
        let saturate = m.saturate(y);
4034
        let sign = m.sign(y);
4035
        let sin = m.sin(y);
4036
        let sqrt = m.sqrt(y);
4037
        let tan = m.tan(y);
4038
        let unpack4x8snorm = m.unpack4x8snorm(us);
4039
        let unpack4x8unorm = m.unpack4x8unorm(uu);
4040
        let comp_x = m.x(w);
4041
        let comp_y = m.y(w);
4042
        let comp_z = m.z(w);
4043
        let comp_w = m.w(w);
4044

4045
        let property_layout = PropertyLayout::default();
4046
        let particle_layout = ParticleLayout::default();
4047
        let mut ctx =
4048
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4049

4050
        for (expr, op, inner) in [
4051
            (
4052
                abs,
4053
                "abs",
4054
                &format!("particle.{}", Attribute::POSITION.name())[..],
4055
            ),
4056
            (all, "all", "vec3<bool>(false,true,false)"),
4057
            (any, "any", "vec3<bool>(false,true,false)"),
4058
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
4059
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
4060
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
4061
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
4062
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
4063
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
4064
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
4065
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
4066
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
4067
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
4068
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
4069
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4070
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4071
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4072
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4073
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4074
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4075
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4076
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4077
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4078
        ] {
4079
            let expr = ctx.eval(&m, expr);
4080
            assert!(expr.is_ok());
4081
            let expr = expr.unwrap();
4082
            assert_eq!(expr, format!("{}({})", op, inner));
4083
        }
4084

4085
        for (expr, op, inner) in [
4086
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4087
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4088
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4089
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4090
        ] {
4091
            let expr = ctx.eval(&m, expr);
4092
            assert!(expr.is_ok());
4093
            let expr = expr.unwrap();
4094
            assert_eq!(expr, format!("{}.{}", inner, op));
4095
        }
4096
    }
4097

4098
    #[test]
4099
    fn binary_expr() {
4100
        let mut m = Module::default();
4101

4102
        let x = m.attr(Attribute::POSITION);
4103
        let y = m.lit(Vec3::ONE);
4104

4105
        let cross = m.cross(x, y);
4106
        let dist = m.distance(x, y);
4107
        let dot = m.dot(x, y);
4108
        let min = m.min(x, y);
4109
        let max = m.max(x, y);
4110
        let step = m.step(x, y);
4111

4112
        let property_layout = PropertyLayout::default();
4113
        let particle_layout = ParticleLayout::default();
4114
        let mut ctx =
4115
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4116

4117
        for (expr, op) in [
4118
            (cross, "cross"),
4119
            (dist, "distance"),
4120
            (dot, "dot"),
4121
            (min, "min"),
4122
            (max, "max"),
4123
            (step, "step"),
4124
        ] {
4125
            let expr = ctx.eval(&m, expr);
4126
            assert!(expr.is_ok());
4127
            let expr = expr.unwrap();
4128
            assert_eq!(
4129
                expr,
4130
                format!(
4131
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4132
                    op,
4133
                    Attribute::POSITION.name(),
4134
                )
4135
            );
4136
        }
4137
    }
4138

4139
    #[test]
4140
    fn ternary_expr() {
4141
        let mut m = Module::default();
4142

4143
        let x = m.attr(Attribute::POSITION);
4144
        let y = m.lit(Vec3::ONE);
4145
        let t = m.lit(0.3);
4146

4147
        let mix = m.mix(x, y, t);
4148
        let smoothstep = m.smoothstep(x, y, x);
4149

4150
        let property_layout = PropertyLayout::default();
4151
        let particle_layout = ParticleLayout::default();
4152
        let mut ctx =
4153
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4154

4155
        for (expr, op, third) in [(mix, "mix", t), (smoothstep, "smoothstep", x)] {
4156
            let expr = ctx.eval(&m, expr);
4157
            assert!(expr.is_ok());
4158
            let expr = expr.unwrap();
4159
            let third = ctx.eval(&m, third).unwrap();
4160
            assert_eq!(
4161
                expr,
4162
                format!(
4163
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4164
                    op,
4165
                    Attribute::POSITION.name(),
4166
                    third
4167
                )
4168
            );
4169
        }
4170
    }
4171

4172
    #[test]
4173
    fn cast_expr() {
4174
        let mut m = Module::default();
4175

4176
        let x = m.attr(Attribute::POSITION);
4177
        let y = m.lit(IVec2::ONE);
4178
        let z = m.lit(0.3);
4179
        let w = m.lit(false);
4180

4181
        let cx = m.cast(x, VectorType::VEC3I);
4182
        let cy = m.cast(y, VectorType::VEC2U);
4183
        let cz = m.cast(z, ScalarType::Int);
4184
        let cw = m.cast(w, ScalarType::Uint);
4185

4186
        let property_layout = PropertyLayout::default();
4187
        let particle_layout = ParticleLayout::default();
4188
        let mut ctx =
4189
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4190

4191
        for (expr, cast, target) in [
4192
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4193
            (y, cy, VectorType::VEC2U.into()),
4194
            (z, cz, ScalarType::Int.into()),
4195
            (w, cw, ScalarType::Uint.into()),
4196
        ] {
4197
            let expr = ctx.eval(&m, expr);
4198
            assert!(expr.is_ok());
4199
            let expr = expr.unwrap();
4200
            let cast = ctx.eval(&m, cast);
4201
            assert!(cast.is_ok());
4202
            let cast = cast.unwrap();
4203
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4204
        }
4205
    }
4206

4207
    #[test]
4208
    fn attribute_pointer() {
4209
        let mut m = Module::default();
4210
        let x = m.attr(Attribute::POSITION);
4211

4212
        let property_layout = PropertyLayout::default();
4213
        let particle_layout = ParticleLayout::default();
4214
        let mut ctx =
4215
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4216

4217
        let res = ctx.eval(&m, x);
4218
        assert!(res.is_ok());
4219
        let xx = res.ok().unwrap();
4220
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4221

4222
        // Use a different context; it's invalid to reuse a mutated context, as the
4223
        // expression cache will have been generated with the wrong context.
4224
        let mut ctx =
4225
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4226
                .with_attribute_pointer();
4227

4228
        let res = ctx.eval(&m, x);
4229
        assert!(res.is_ok());
4230
        let xx = res.ok().unwrap();
4231
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4232
    }
4233

4234
    #[test]
4235
    #[should_panic]
4236
    fn invalid_cast_vector_to_scalar() {
4237
        let mut m = Module::default();
4238
        let x = m.lit(Vec2::ONE);
4239
        let _ = m.cast(x, ScalarType::Float);
4240
    }
4241

4242
    #[test]
4243
    #[should_panic]
4244
    fn invalid_cast_matrix_to_scalar() {
4245
        let mut m = Module::default();
4246
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4247
        let _ = m.cast(x, ScalarType::Float);
4248
    }
4249

4250
    #[test]
4251
    #[should_panic]
4252
    fn invalid_cast_matrix_to_vector() {
4253
        let mut m = Module::default();
4254
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4255
        let _ = m.cast(x, VectorType::VEC4F);
4256
    }
4257

4258
    #[test]
4259
    #[should_panic]
4260
    fn invalid_cast_scalar_to_matrix() {
4261
        let mut m = Module::default();
4262
        let x = m.lit(3.);
4263
        let _ = m.cast(x, MatrixType::MAT3X3F);
4264
    }
4265

4266
    #[test]
4267
    #[should_panic]
4268
    fn invalid_cast_vector_to_matrix() {
4269
        let mut m = Module::default();
4270
        let x = m.lit(Vec3::ZERO);
4271
        let _ = m.cast(x, MatrixType::MAT2X4F);
4272
    }
4273

4274
    #[test]
4275
    fn cast_expr_new() {
4276
        let mut m = Module::default();
4277

4278
        let x = m.attr(Attribute::POSITION);
4279
        let c = CastExpr::new(x, VectorType::VEC3F);
4280
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4281
        assert_eq!(c.is_valid(&m), Some(true));
4282

4283
        let x = m.attr(Attribute::POSITION);
4284
        let c = CastExpr::new(x, ScalarType::Bool);
4285
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4286
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4287

4288
        let p = m.add_property("my_prop", 3.0.into());
4289
        let y = m.prop(p);
4290
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4291
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4292
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4293
    }
4294

4295
    #[test]
4296
    fn side_effect() {
4297
        let mut m = Module::default();
4298

4299
        // Adding the same cloned expression with side effect to itself should yield
4300
        // twice the value, and not two separate evaluations of the expression.
4301
        // CORRECT:
4302
        //   let r = frand();
4303
        //   r + r
4304
        // INCORRECT:
4305
        //   frand() + frand()
4306

4307
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4308
        let r2 = r;
4309
        let r3 = r2;
4310
        let a = m.add(r, r2);
4311
        let b = m.mix(r, r2, r3);
4312
        let c = m.abs(a);
4313

4314
        {
4315
            let property_layout = PropertyLayout::default();
4316
            let particle_layout = ParticleLayout::default();
4317
            let mut ctx =
4318
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4319
            let value = ctx.eval(&m, a).unwrap();
4320
            assert_eq!(value, "(var0) + (var0)");
4321
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4322
        }
4323

4324
        {
4325
            let property_layout = PropertyLayout::default();
4326
            let particle_layout = ParticleLayout::default();
4327
            let mut ctx =
4328
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4329
            let value = ctx.eval(&m, b).unwrap();
4330
            assert_eq!(value, "mix(var0, var0, var0)");
4331
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4332
        }
4333

4334
        {
4335
            let property_layout = PropertyLayout::default();
4336
            let particle_layout = ParticleLayout::default();
4337
            let mut ctx =
4338
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4339
            let value = ctx.eval(&m, c).unwrap();
4340
            assert_eq!(value, "abs((var0) + (var0))");
4341
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4342
        }
4343
    }
4344

4345
    // #[test]
4346
    // fn serde() {
4347
    //     let v = Value::Scalar(3.0_f32.into());
4348
    //     let l: LiteralExpr = v.into();
4349
    //     assert_eq!(Ok(v), l.eval());
4350
    //     let s = ron::to_string(&l).unwrap();
4351
    //     println!("literal: {:?}", s);
4352
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4353
    //     assert_eq!(l_serde, l);
4354

4355
    //     let b: ExprHandle = Box::new(l);
4356
    //     let s = ron::to_string(&b).unwrap();
4357
    //     println!("boxed literal: {:?}", s);
4358
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4359
    //     assert!(b_serde.is_const());
4360
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4361

4362
    //     let v0 = Value::Scalar(3.0_f32.into());
4363
    //     let v1 = Value::Scalar(2.5_f32.into());
4364
    //     let l0: LiteralExpr = v0.into();
4365
    //     let l1: LiteralExpr = v1.into();
4366
    //     let a = l0 + l1;
4367
    //     assert!(a.is_const());
4368
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4369
    //     let s = ron::to_string(&a).unwrap();
4370
    //     println!("add: {:?}", s);
4371
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4372
    //     println!("a_serde: {:?}", a_serde);
4373
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4374
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4375
    // }
4376
}
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