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

djeedai / bevy_hanabi / 12128238298

02 Dec 2024 09:24PM UTC coverage: 48.661% (-7.6%) from 56.217%
12128238298

Pull #401

github

web-flow
Merge 30c486d1a into 19aee8dbc
Pull Request #401: Upgrade to Bevy v0.15.0

39 of 284 new or added lines in 11 files covered. (13.73%)

435 existing lines in 8 files now uncovered.

3106 of 6383 relevant lines covered (48.66%)

21.61 hits per line

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

54.42
/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 {
392✔
155
        (self.id.get() - 1) as usize
392✔
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
NEW
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.
UNCOV
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 property expression and append it to the module.
420
    ///
421
    /// A property expression retrieves the value of the given property.
422
    #[inline]
423
    pub fn prop(&mut self, property: PropertyHandle) -> ExprHandle {
3✔
424
        self.push(Expr::Property(PropertyExpr::new(property)))
3✔
425
    }
426

427
    /// Build a built-in expression and append it to the module.
428
    #[inline]
429
    pub fn builtin(&mut self, op: BuiltInOperator) -> ExprHandle {
30✔
430
        self.push(Expr::BuiltIn(BuiltInExpr::new(op)))
30✔
431
    }
432

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

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

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

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

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

562
    impl_module_ternary!(mix, Mix);
563
    impl_module_ternary!(smoothstep, SmoothStep);
564

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

593
    /// Get an existing expression from its handle.
594
    #[inline]
595
    pub fn get(&self, expr: ExprHandle) -> Option<&Expr> {
22✔
596
        let index = expr.index();
22✔
597
        self.expressions.get(index)
22✔
598
    }
599

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

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

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

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

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

653
    /// Get the texture layout of this module.
654
    pub fn texture_layout(&self) -> TextureLayout {
25✔
655
        self.texture_layout.clone()
25✔
656
    }
657
}
658

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

671
    /// Expression syntax error.
672
    #[error("Syntax error: {0}")]
673
    SyntaxError(String),
674

675
    /// Generic graph evaluation error.
676
    #[error("Graph evaluation error: {0}")]
677
    GraphEvalError(String),
678

679
    /// Error resolving a property.
680
    ///
681
    /// An unknown property was not defined in the evaluation context, which
682
    /// usually means that the property was not defined with
683
    /// [`Module::add_property()`].
684
    #[error("Property error: {0}")]
685
    PropertyError(String),
686

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

698
    /// Invalid modifier context.
699
    ///
700
    /// The operation was expecting a given [`ModifierContext`], but instead
701
    /// another [`ModifierContext`] was available.
702
    #[error("Invalid modifier context {0}, expected {1} instead.")]
703
    InvalidModifierContext(ModifierContext, ModifierContext),
704
}
705

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

722
    /// Get the particle layout of the effect.
723
    fn particle_layout(&self) -> &ParticleLayout;
724

725
    /// Get the property layout of the effect.
726
    fn property_layout(&self) -> &PropertyLayout;
727

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

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

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

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

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

787
/// Language expression producing a value.
788
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
789
pub enum Expr {
790
    /// Built-in expression ([`BuiltInExpr`]).
791
    ///
792
    /// A built-in expression provides access to some internal
793
    /// quantities like the simulation time.
794
    BuiltIn(BuiltInExpr),
795

796
    /// Literal expression ([`LiteralExpr`]).
797
    ///
798
    /// A literal expression represents a shader constants.
799
    Literal(LiteralExpr),
800

801
    /// Property expression ([`PropertyExpr`]).
802
    ///
803
    /// A property expression represents the value of an [`EffectAsset`]'s
804
    /// property.
805
    ///
806
    /// [`EffectAsset`]: crate::EffectAsset
807
    Property(PropertyExpr),
808

809
    /// Attribute expression ([`AttributeExpr`]).
810
    ///
811
    /// An attribute expression represents the value of an attribute for a
812
    /// particle, like its position or velocity.
813
    Attribute(AttributeExpr),
814

815
    /// Unary operation expression.
816
    ///
817
    /// A unary operation transforms an expression into another expression.
818
    Unary {
819
        /// Unary operator.
820
        op: UnaryOperator,
821
        /// Operand the unary operation applies to.
822
        expr: ExprHandle,
823
    },
824

825
    /// Binary operation expression.
826
    ///
827
    /// A binary operation composes two expressions into a third one.
828
    Binary {
829
        /// Binary operator.
830
        op: BinaryOperator,
831
        /// Left-hand side operand the binary operation applies to.
832
        left: ExprHandle,
833
        /// Right-hand side operand the binary operation applies to.
834
        right: ExprHandle,
835
    },
836

837
    /// Ternary operation expression.
838
    ///
839
    /// A ternary operation composes three expressions into a fourth one.
840
    Ternary {
841
        /// Ternary operator.
842
        op: TernaryOperator,
843
        /// First operand the ternary operation applies to.
844
        first: ExprHandle,
845
        /// Second operand the ternary operation applies to.
846
        second: ExprHandle,
847
        /// Third operand the ternary operation applies to.
848
        third: ExprHandle,
849
    },
850

851
    /// Cast expression.
852
    ///
853
    /// An expression to cast an expression to another type.
854
    Cast(CastExpr),
855

856
    /// Access to textures.
857
    ///
858
    /// An expression to sample a texture from the effect's material. Currently
859
    /// only color textures (returning a `vec4<f32>`) are supported.
860
    TextureSample(TextureSampleExpr),
861
}
862

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

909
    /// Has the expression any side-effect?
910
    ///
911
    /// Expressions with side-effect need to be stored into temporary variables
912
    /// when the shader code is emitted, so that the side effect is only applied
913
    /// once when the expression is reused in multiple locations.
914
    pub fn has_side_effect(&self, module: &Module) -> bool {
×
915
        match self {
×
916
            Expr::BuiltIn(expr) => expr.has_side_effect(),
×
917
            Expr::Literal(_) => false,
×
918
            Expr::Property(_) => false,
×
919
            Expr::Attribute(_) => false,
×
920
            Expr::Unary { expr, .. } => module.has_side_effect(*expr),
×
921
            Expr::Binary { left, right, op } => {
×
922
                (*op == BinaryOperator::UniformRand || *op == BinaryOperator::NormalRand)
×
923
                    || module.has_side_effect(*left)
×
924
                    || module.has_side_effect(*right)
×
925
            }
926
            Expr::Ternary {
927
                first,
×
928
                second,
×
929
                third,
×
930
                ..
×
931
            } => {
×
932
                module.has_side_effect(*first)
×
933
                    || module.has_side_effect(*second)
×
934
                    || module.has_side_effect(*third)
×
935
            }
936
            Expr::Cast(expr) => module.has_side_effect(expr.inner),
×
937
            Expr::TextureSample(_) => false,
×
938
        }
939
    }
940

941
    /// The type of the value produced by the expression.
942
    ///
943
    /// If the type is variable and depends on the runtime evaluation context,
944
    /// this returns `None`. In that case the type needs to be obtained by
945
    /// evaluating the expression with [`eval()`].
946
    ///
947
    /// # Example
948
    ///
949
    /// ```
950
    /// # use bevy_hanabi::*;
951
    /// // Literal expressions always have a constant, build-time value type.
952
    /// let expr = Expr::Literal(LiteralExpr::new(1.));
953
    /// assert_eq!(
954
    ///     expr.value_type(),
955
    ///     Some(ValueType::Scalar(ScalarType::Float))
956
    /// );
957
    /// ```
958
    ///
959
    /// [`eval()`]: crate::graph::Expr::eval
960
    pub fn value_type(&self) -> Option<ValueType> {
21✔
961
        match self {
21✔
962
            Expr::BuiltIn(expr) => Some(expr.value_type()),
×
963
            Expr::Literal(expr) => Some(expr.value_type()),
17✔
964
            Expr::Property(_) => None,
1✔
965
            Expr::Attribute(expr) => Some(expr.value_type()),
3✔
966
            Expr::Unary { .. } => None,
×
967
            Expr::Binary { .. } => None,
×
968
            Expr::Ternary { .. } => None,
×
969
            Expr::Cast(expr) => Some(expr.value_type()),
×
970
            Expr::TextureSample(expr) => Some(expr.value_type()),
×
971
        }
972
    }
973

974
    /// Evaluate the expression in the given context.
975
    ///
976
    /// Evaluate the full expression as part of the given evaluation context,
977
    /// returning the WGSL string representation of the expression on success.
978
    ///
979
    /// The evaluation context is used to resolve some quantities related to the
980
    /// effect asset, like its properties. It also holds the [`Module`] that the
981
    /// expression is part of, to allow resolving sub-expressions of operators.
982
    ///
983
    /// # Example
984
    ///
985
    /// ```
986
    /// # use bevy_hanabi::*;
987
    /// let mut module = Module::default();
988
    /// # let pl = PropertyLayout::empty();
989
    /// # let pal = ParticleLayout::default();
990
    /// # let mut context = ShaderWriter::new(ModifierContext::Update, &pl, &pal);
991
    /// let handle = module.lit(1.);
992
    /// let expr = module.get(handle).unwrap();
993
    /// assert_eq!(Ok("1.".to_string()), expr.eval(&module, &mut context));
994
    /// ```
995
    pub fn eval(
237✔
996
        &self,
997
        module: &Module,
998
        context: &mut dyn EvalContext,
999
    ) -> Result<String, ExprError> {
1000
        match self {
237✔
1001
            Expr::BuiltIn(expr) => expr.eval(context),
34✔
1002
            Expr::Literal(expr) => expr.eval(context),
96✔
1003
            Expr::Property(expr) => expr.eval(module, context),
2✔
1004
            Expr::Attribute(expr) => expr.eval(context),
26✔
1005
            Expr::Unary { op, expr } => {
34✔
1006
                // Recursively evaluate child expressions throught the context to ensure caching
1007
                let expr = context.eval(module, *expr)?;
68✔
1008

1009
                // if expr.value_type() != self.value_type() {
1010
                //     return Err(ExprError::TypeError(format!(
1011
                //         "Cannot apply normalize() function to non-vector expression: {}",
1012
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1013
                //     )));
1014
                // }
1015

1016
                Ok(if op.is_functional() {
1017
                    format!("{}({})", op.to_wgsl_string(), expr)
30✔
1018
                } else {
1019
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1020
                })
1021
            }
1022
            Expr::Binary { op, left, right } => {
38✔
1023
                // Recursively evaluate child expressions throught the context to ensure caching
1024
                let compiled_left = context.eval(module, *left)?;
76✔
1025
                let compiled_right = context.eval(module, *right)?;
38✔
1026

1027
                // if !self.input.value_type().is_vector() {
1028
                //     return Err(ExprError::TypeError(format!(
1029
                //         "Cannot apply normalize() function to non-vector expression: {}",
1030
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1031
                //     )));
1032
                // }
1033

1034
                if op.is_functional() {
1035
                    if op.needs_type_suffix() {
11✔
1036
                        let lhs_type = module.get(*left).and_then(|arg| arg.value_type());
×
1037
                        let rhs_type = module.get(*right).and_then(|arg| arg.value_type());
×
1038
                        if lhs_type.is_none() || rhs_type.is_none() {
×
1039
                            return Err(ExprError::TypeError(
×
1040
                                "Can't determine the type of the operand".to_string(),
×
1041
                            ));
1042
                        }
1043
                        if lhs_type != rhs_type {
×
1044
                            return Err(ExprError::TypeError("Mismatched types".to_string()));
×
1045
                        }
1046
                        let value_type = lhs_type.unwrap();
×
1047
                        let suffix = match value_type {
×
1048
                            ValueType::Scalar(ScalarType::Float) => "f",
×
1049
                            ValueType::Vector(vector_type)
×
1050
                                if vector_type.elem_type() == ScalarType::Float =>
×
1051
                            {
1052
                                match vector_type.count() {
1053
                                    2 => "vec2",
×
1054
                                    3 => "vec3",
×
1055
                                    4 => "vec4",
×
1056
                                    _ => unreachable!(),
1057
                                }
1058
                            }
1059
                            _ => {
1060
                                // Add more types here as needed.
1061
                                return Err(ExprError::TypeError("Unsupported type".to_string()));
×
1062
                            }
1063
                        };
1064

1065
                        Ok(format!(
1066
                            "{}_{}({}, {})",
1067
                            op.to_wgsl_string(),
1068
                            suffix,
1069
                            compiled_left,
1070
                            compiled_right
1071
                        ))
1072
                    } else {
1073
                        Ok(format!(
11✔
1074
                            "{}({}, {})",
11✔
1075
                            op.to_wgsl_string(),
11✔
1076
                            compiled_left,
11✔
1077
                            compiled_right
11✔
1078
                        ))
1079
                    }
1080
                } else {
1081
                    Ok(format!(
27✔
1082
                        "({}) {} ({})",
27✔
1083
                        compiled_left,
27✔
1084
                        op.to_wgsl_string(),
27✔
1085
                        compiled_right
27✔
1086
                    ))
1087
                }
1088
            }
1089
            Expr::Ternary {
1090
                op,
3✔
1091
                first,
3✔
1092
                second,
3✔
1093
                third,
3✔
1094
            } => {
1095
                // Recursively evaluate child expressions throught the context to ensure caching
1096
                let first = context.eval(module, *first)?;
6✔
1097
                let second = context.eval(module, *second)?;
3✔
1098
                let third = context.eval(module, *third)?;
3✔
1099

1100
                // if !self.input.value_type().is_vector() {
1101
                //     return Err(ExprError::TypeError(format!(
1102
                //         "Cannot apply normalize() function to non-vector expression: {}",
1103
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1104
                //     )));
1105
                // }
1106

1107
                Ok(format!(
3✔
1108
                    "{}({}, {}, {})",
3✔
1109
                    op.to_wgsl_string(),
3✔
1110
                    first,
3✔
1111
                    second,
3✔
1112
                    third
3✔
1113
                ))
1114
            }
1115
            Expr::Cast(expr) => {
4✔
1116
                // Recursively evaluate child expressions throught the context to ensure caching
1117
                let inner = context.eval(module, expr.inner)?;
8✔
1118

1119
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
4✔
1120
            }
1121
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1122
        }
1123
    }
1124
}
1125

1126
/// A literal constant expression like `3.0` or `vec3<f32>(1.0, 2.0, 3.0)`.
1127
///
1128
/// Literal expression are compile-time constants. They are always constant
1129
/// ([`is_const()`] is `true`) and have a value type equal to the type of the
1130
/// constant itself.
1131
///
1132
/// [`is_const()`]: LiteralExpr::is_const
1133
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
1134
#[serde(transparent)]
1135
pub struct LiteralExpr {
1136
    value: Value,
1137
}
1138

1139
impl LiteralExpr {
1140
    /// Create a new literal expression from a [`Value`].
1141
    pub fn new<V>(value: V) -> Self
76✔
1142
    where
1143
        Value: From<V>,
1144
    {
1145
        Self {
1146
            value: value.into(),
76✔
1147
        }
1148
    }
1149

1150
    /// Is the expression resulting in a compile-time constant which can be
1151
    /// hard-coded into a shader's code?
1152
    pub fn is_const(&self) -> bool {
×
1153
        true
×
1154
    }
1155

1156
    /// Get the value type of the expression.
1157
    pub fn value_type(&self) -> ValueType {
17✔
1158
        self.value.value_type()
17✔
1159
    }
1160

1161
    /// Evaluate the expression in the given context.
1162
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
96✔
1163
        Ok(self.value.to_wgsl_string())
96✔
1164
    }
1165
}
1166

1167
impl ToWgslString for LiteralExpr {
1168
    fn to_wgsl_string(&self) -> String {
×
1169
        self.value.to_wgsl_string()
×
1170
    }
1171
}
1172

1173
impl From<&Value> for LiteralExpr {
1174
    fn from(value: &Value) -> Self {
×
1175
        Self { value: *value }
×
1176
    }
1177
}
1178

1179
impl<T: Into<Value>> From<T> for LiteralExpr {
1180
    fn from(value: T) -> Self {
×
1181
        Self {
1182
            value: value.into(),
×
1183
        }
1184
    }
1185
}
1186

1187
/// Expression representing the value of an attribute of a particle.
1188
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1189
pub struct AttributeExpr {
1190
    attr: Attribute,
1191
}
1192

1193
impl AttributeExpr {
1194
    /// Create a new attribute expression.
1195
    #[inline]
1196
    pub fn new(attr: Attribute) -> Self {
27✔
1197
        Self { attr }
1198
    }
1199

1200
    /// Is the expression resulting in a compile-time constant which can be
1201
    /// hard-coded into a shader's code?
1202
    pub fn is_const(&self) -> bool {
×
1203
        false
×
1204
    }
1205

1206
    /// Get the value type of the expression.
1207
    pub fn value_type(&self) -> ValueType {
3✔
1208
        self.attr.value_type()
3✔
1209
    }
1210

1211
    /// Evaluate the expression in the given context.
1212
    pub fn eval(&self, context: &dyn EvalContext) -> Result<String, ExprError> {
26✔
1213
        if context.is_attribute_pointer() {
26✔
1214
            Ok(format!("(*particle).{}", self.attr.name()))
2✔
1215
        } else {
1216
            Ok(format!("particle.{}", self.attr.name()))
24✔
1217
        }
1218
    }
1219
}
1220

1221
impl ToWgslString for AttributeExpr {
1222
    fn to_wgsl_string(&self) -> String {
×
1223
        format!("particle.{}", self.attr.name())
×
1224
    }
1225
}
1226

1227
impl From<Attribute> for AttributeExpr {
1228
    fn from(value: Attribute) -> Self {
×
1229
        AttributeExpr::new(value)
×
1230
    }
1231
}
1232

1233
/// Expression representing the value of a property of an effect.
1234
///
1235
/// A property expression represents the value of the property at the time the
1236
/// expression appears. In shader, the expression yields a read from the
1237
/// property memory location.
1238
///
1239
/// To create a property to reference with an expression, use
1240
/// [`Module::add_property()`].
1241
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1242
#[repr(transparent)]
1243
#[serde(transparent)]
1244
pub struct PropertyExpr {
1245
    property: PropertyHandle,
1246
}
1247

1248
impl PropertyExpr {
1249
    /// Create a new property expression.
1250
    #[inline]
1251
    pub fn new(property: PropertyHandle) -> Self {
4✔
1252
        Self { property }
1253
    }
1254

1255
    /// Is the expression resulting in a compile-time constant which can be
1256
    /// hard-coded into a shader's code?
1257
    fn is_const(&self) -> bool {
×
1258
        false
×
1259
    }
1260

1261
    /// Evaluate the expression in the given context.
1262
    fn eval(&self, module: &Module, context: &dyn EvalContext) -> Result<String, ExprError> {
2✔
1263
        let prop = module
4✔
1264
            .get_property(self.property)
2✔
1265
            .ok_or(ExprError::PropertyError(format!(
2✔
1266
                "Unknown property handle {:?} in evaluation module.",
2✔
1267
                self.property
2✔
1268
            )))?;
1269
        if !context.property_layout().contains(prop.name()) {
1270
            return Err(ExprError::PropertyError(format!(
×
1271
                "Unknown property '{}' in evaluation layout.",
×
1272
                prop.name()
×
1273
            )));
1274
        }
1275

1276
        Ok(format!("properties.{}", prop.name()))
2✔
1277
    }
1278
}
1279

1280
/// Expression to cast an expression to another type.
1281
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1282
pub struct CastExpr {
1283
    /// The operand expression to cast.
1284
    inner: ExprHandle,
1285
    /// The target type to cast to.
1286
    target: ValueType,
1287
}
1288

1289
impl CastExpr {
1290
    /// Create a new cast expression.
1291
    #[inline]
1292
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1293
        Self {
1294
            inner,
1295
            target: target.into(),
12✔
1296
        }
1297
    }
1298

1299
    /// Get the value type of the expression.
1300
    pub fn value_type(&self) -> ValueType {
3✔
1301
        self.target
3✔
1302
    }
1303

1304
    /// Try to evaluate if the cast expression is valid.
1305
    ///
1306
    /// The evaluation fails if the value type of the operand cannot be
1307
    /// determined. In that case, the function returns `None`.
1308
    ///
1309
    /// Valid cast expressions are:
1310
    /// - scalar to scalar
1311
    /// - scalar to vector
1312
    /// - vector to vector
1313
    /// - matrix to matrix
1314
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
12✔
1315
        let Some(inner) = module.get(self.inner) else {
24✔
1316
            return Some(false);
×
1317
        };
1318
        if let Some(inner_type) = inner.value_type() {
11✔
1319
            match self.target {
1320
                ValueType::Scalar(_) => {
1321
                    // scalar -> scalar only
1322
                    Some(matches!(inner_type, ValueType::Scalar(_)))
8✔
1323
                }
1324
                ValueType::Vector(_) => {
1325
                    // {scalar, vector} -> vector
1326
                    Some(!matches!(inner_type, ValueType::Matrix(_)))
7✔
1327
                }
1328
                ValueType::Matrix(_) => {
1329
                    // matrix -> matrix only
1330
                    Some(matches!(inner_type, ValueType::Matrix(_)))
4✔
1331
                }
1332
            }
1333
        } else {
1334
            None
1✔
1335
        }
1336
    }
1337
}
1338

1339
/// Expression to sample a texture from the effect's material.
1340
///
1341
/// This currently supports only 4-component textures sampled with [the WGSL
1342
/// `textureSample()` function], that is all textures which return a `vec4<f32>`
1343
/// when sampled. This is the case of most color textures, including
1344
/// single-channel (e.g. red) textures which return zero for missing components,
1345
/// but excludes depth textures.
1346
///
1347
/// [the WGSL `textureSample()` function]: https://www.w3.org/TR/WGSL/#texturesample
1348
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1349
pub struct TextureSampleExpr {
1350
    /// The index of the image to sample. This is the texture slot defined in
1351
    /// the [`Module`]. The texture bound to the slot is defined in the
1352
    /// [`EffectMaterial`] component.
1353
    ///
1354
    /// [`EffectMaterial`]: crate::EffectMaterial
1355
    pub image: ExprHandle,
1356
    /// The coordinates to sample at.
1357
    pub coordinates: ExprHandle,
1358
}
1359

1360
impl TextureSampleExpr {
1361
    /// Create a new texture sample expression.
1362
    #[inline]
1363
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1364
        Self { image, coordinates }
1365
    }
1366

1367
    /// Get the value type of the expression.
1368
    pub fn value_type(&self) -> ValueType {
×
1369
        // FIXME - depth textures return a single f32 when sampled
1370
        ValueType::Vector(VectorType::VEC4F)
×
1371
    }
1372

1373
    /// Try to evaluate if the texture sample expression is valid.
1374
    ///
1375
    /// This only checks that the expressions exist in the module.
1376
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
×
1377
        let Some(_image) = module.get(self.image) else {
×
1378
            return Some(false);
×
1379
        };
1380
        let Some(_coordinates) = module.get(self.coordinates) else {
×
1381
            return Some(false);
×
1382
        };
1383
        Some(true)
×
1384
    }
1385

1386
    /// Evaluate the expression in the given context.
1387
    pub fn eval(
×
1388
        &self,
1389
        module: &Module,
1390
        context: &mut dyn EvalContext,
1391
    ) -> Result<String, ExprError> {
1392
        let image = module.try_get(self.image)?;
×
1393
        let image = image.eval(module, context)?;
×
1394
        let coordinates = module.try_get(self.coordinates)?;
×
1395
        let coordinates = coordinates.eval(module, context)?;
×
1396
        Ok(format!(
×
1397
            "textureSample(material_texture_{image}, material_sampler_{image}, {coordinates})",
×
1398
        ))
1399
    }
1400
}
1401

1402
/// Built-in operators.
1403
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1404
pub enum BuiltInOperator {
1405
    /// Current effect system simulation time since startup, in seconds.
1406
    ///
1407
    /// This is based on the
1408
    /// [`Time<EffectSimulation>`](crate::time::EffectSimulation) clock.
1409
    ///
1410
    /// Type: `f32`
1411
    Time,
1412
    /// Delta time, in seconds, since last effect system update.
1413
    ///
1414
    /// Type: `f32`
1415
    DeltaTime,
1416
    /// Current virtual time since startup, in seconds.
1417
    ///
1418
    /// This is based on the [`Time<Virtual>`](bevy::time::Virtual) clock.
1419
    ///
1420
    /// Type: `f32`
1421
    VirtualTime,
1422
    /// Virtual delta time, in seconds, since last effect system update.
1423
    ///
1424
    /// Type: `f32`
1425
    VirtualDeltaTime,
1426
    /// Current real time since startup, in seconds.
1427
    ///
1428
    /// This is based on the [`Time<Time>`](bevy::time::Real) clock.
1429
    ///
1430
    /// Type: `f32`
1431
    RealTime,
1432
    /// Real delta time, in seconds, since last effect system update.
1433
    ///
1434
    /// Type: `f32`
1435
    RealDeltaTime,
1436
    /// Random unit value of the given type.
1437
    ///
1438
    /// The type can be any scalar or vector type. Matrix types are not
1439
    /// supported. The random values generated are uniformly distributed in
1440
    /// `[0:1]`. For vectors, each component is sampled separately.
1441
    ///
1442
    /// The random number generator is from [the PCG family] of PRNGs, and is
1443
    /// implemented directly inside the shader, and running on the GPU
1444
    /// exclusively. It's seeded by the [`Spawner`].
1445
    ///
1446
    /// Type: Same as its [`ValueType`].
1447
    ///
1448
    /// [the PCG family]: https://www.pcg-random.org/
1449
    /// [`Spawner`]: crate::Spawner
1450
    Rand(ValueType),
1451
    /// Value of the alpha cutoff for alpha masking.
1452
    ///
1453
    /// This value is only available in the render context. It represents the
1454
    /// current threshold, generally in \[0:1\], which the particle's fragment
1455
    /// alpha value will be compared against to determine alpha masking.
1456
    ///
1457
    /// The value is initalized at the beginning of the fragment shader to the
1458
    /// expression stored in [`AlphaMode::Mask`].
1459
    ///
1460
    /// Type: `f32`
1461
    ///
1462
    /// [`AlphaMode::Mask`]: crate::AlphaMode::Mask
1463
    AlphaCutoff,
1464
    /// Alive flag for the particle.
1465
    ///
1466
    /// The alive flag is initialized at the beginning of the update pass:
1467
    /// - If the particle has both the [`Attribute::AGE`] and
1468
    ///   [`Attribute::LIFETIME`], then the initial value at the beginning of
1469
    ///   the update pass is `age < lifetime`.
1470
    /// - Otherwise, the initial value is `true`.
1471
    ///
1472
    /// At the end of the update pass, if the particle has both the
1473
    /// [`Attribute::AGE`] and   [`Attribute::LIFETIME`], then the flag is
1474
    /// re-evaluated as:
1475
    ///
1476
    /// ```wgsl
1477
    /// is_alive = is_alive && (particle.age < particle.lifetime);
1478
    /// ```
1479
    ///
1480
    /// If the flag is `false` after that, the particle is considered dead and
1481
    /// it's deallocated.
1482
    ///
1483
    /// This flag is only available in the update pass. Attempting to use it
1484
    /// inside either the init or render passes will generate an invalid shader.
1485
    ///
1486
    /// Type: `bool`
1487
    IsAlive,
1488
}
1489

1490
impl BuiltInOperator {
1491
    /// Get the operator name.
1492
    pub fn name(&self) -> &str {
49✔
1493
        match self {
49✔
1494
            BuiltInOperator::Time => "time",
6✔
1495
            BuiltInOperator::DeltaTime => "delta_time",
13✔
1496
            BuiltInOperator::VirtualTime => "virtual_time",
2✔
1497
            BuiltInOperator::VirtualDeltaTime => "virtual_delta_time",
2✔
1498
            BuiltInOperator::RealTime => "real_time",
2✔
1499
            BuiltInOperator::RealDeltaTime => "real_delta_time",
2✔
1500
            BuiltInOperator::Rand(value_type) => match value_type {
22✔
1501
                ValueType::Scalar(s) => match s {
10✔
1502
                    ScalarType::Bool => "brand",
1✔
1503
                    ScalarType::Float => "frand",
7✔
1504
                    ScalarType::Int => "irand",
1✔
1505
                    ScalarType::Uint => "urand",
1✔
1506
                },
1507
                ValueType::Vector(vector_type) => {
12✔
1508
                    match (vector_type.elem_type(), vector_type.count()) {
12✔
1509
                        (ScalarType::Bool, 2) => "brand2",
1✔
1510
                        (ScalarType::Bool, 3) => "brand3",
1✔
1511
                        (ScalarType::Bool, 4) => "brand4",
1✔
1512
                        (ScalarType::Float, 2) => "frand2",
1✔
1513
                        (ScalarType::Float, 3) => "frand3",
1✔
1514
                        (ScalarType::Float, 4) => "frand4",
1✔
1515
                        (ScalarType::Int, 2) => "irand2",
1✔
1516
                        (ScalarType::Int, 3) => "irand3",
1✔
1517
                        (ScalarType::Int, 4) => "irand4",
1✔
1518
                        (ScalarType::Uint, 2) => "urand2",
1✔
1519
                        (ScalarType::Uint, 3) => "urand3",
1✔
1520
                        (ScalarType::Uint, 4) => "urand4",
1✔
1521
                        _ => panic!("Invalid vector type {:?}", vector_type),
×
1522
                    }
1523
                }
1524
                ValueType::Matrix(_) => panic!("Invalid BuiltInOperator::Rand(ValueType::Matrix)."),
×
1525
            },
1526
            BuiltInOperator::AlphaCutoff => "alpha_cutoff",
×
1527
            BuiltInOperator::IsAlive => "is_alive",
×
1528
        }
1529
    }
1530

1531
    /// Get the type of the value of a built-in operator.
1532
    pub fn value_type(&self) -> ValueType {
4✔
1533
        match self {
4✔
1534
            BuiltInOperator::Time => ValueType::Scalar(ScalarType::Float),
2✔
1535
            BuiltInOperator::DeltaTime => ValueType::Scalar(ScalarType::Float),
2✔
1536
            BuiltInOperator::VirtualTime => ValueType::Scalar(ScalarType::Float),
×
1537
            BuiltInOperator::VirtualDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1538
            BuiltInOperator::RealTime => ValueType::Scalar(ScalarType::Float),
×
1539
            BuiltInOperator::RealDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1540
            BuiltInOperator::Rand(value_type) => *value_type,
×
1541
            BuiltInOperator::AlphaCutoff => ValueType::Scalar(ScalarType::Float),
×
1542
            BuiltInOperator::IsAlive => ValueType::Scalar(ScalarType::Bool),
×
1543
        }
1544
    }
1545

1546
    // /// Evaluate the result of the operator as an expression.
1547
    // pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
1548
    //     match self {
1549
    //         BuiltInOperator::Time => Value::Scalar(Scal)
1550
    //     }
1551
    // }
1552
}
1553

1554
impl ToWgslString for BuiltInOperator {
1555
    fn to_wgsl_string(&self) -> String {
37✔
1556
        match self {
37✔
1557
            BuiltInOperator::Rand(_) => format!("{}()", self.name()),
22✔
1558
            BuiltInOperator::IsAlive => "is_alive".to_string(),
1✔
1559
            _ => format!("sim_params.{}", self.name()),
14✔
1560
        }
1561
    }
1562
}
1563

1564
/// Expression for getting built-in quantities related to the effect system.
1565
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1566
pub struct BuiltInExpr {
1567
    operator: BuiltInOperator,
1568
}
1569

1570
impl BuiltInExpr {
1571
    /// Create a new built-in operator expression.
1572
    ///
1573
    /// # Panics
1574
    ///
1575
    /// Panics on invalid [`BuiltInOperator`], like `Rand(MatrixType)`. See
1576
    /// each [`BuiltInOperator`] variant for more details.
1577
    #[inline]
1578
    pub fn new(operator: BuiltInOperator) -> Self {
33✔
1579
        if let BuiltInOperator::Rand(value_type) = operator {
51✔
1580
            assert!(!matches!(value_type, ValueType::Matrix(_)));
18✔
1581
        }
1582
        Self { operator }
1583
    }
1584

1585
    /// Is the expression resulting in a compile-time constant?
1586
    ///
1587
    /// Constant expressions can be hard-coded into a shader's code, making them
1588
    /// more efficient and open to shader compiler optimizing.
1589
    pub fn is_const(&self) -> bool {
×
1590
        false
×
1591
    }
1592

1593
    /// Has the expression any side-effect?
1594
    ///
1595
    /// Expressions with side-effect need to be stored into temporary variables
1596
    /// when the shader code is emitted, so that the side effect is only applied
1597
    /// once when the expression is reused in multiple locations.
1598
    pub fn has_side_effect(&self) -> bool {
37✔
1599
        matches!(self.operator, BuiltInOperator::Rand(_))
52✔
1600
    }
1601

1602
    /// Get the value type of the expression.
1603
    ///
1604
    /// The value type of the expression is the type of the value(s) that an
1605
    /// expression produces.
1606
    pub fn value_type(&self) -> ValueType {
×
1607
        self.operator.value_type()
×
1608
    }
1609

1610
    /// Evaluate the expression in the given context.
1611
    pub fn eval(&self, context: &mut dyn EvalContext) -> Result<String, ExprError> {
37✔
1612
        if self.has_side_effect() {
37✔
1613
            let var_name = context.make_local_var();
22✔
1614
            context.push_stmt(&format!("let {} = {};", var_name, self.to_wgsl_string()));
22✔
1615
            Ok(var_name)
22✔
1616
        } else {
1617
            Ok(self.to_wgsl_string())
15✔
1618
        }
1619
    }
1620
}
1621

1622
impl ToWgslString for BuiltInExpr {
1623
    fn to_wgsl_string(&self) -> String {
37✔
1624
        self.operator.to_wgsl_string()
37✔
1625
    }
1626
}
1627

1628
/// Unary operator.
1629
///
1630
/// Operator applied to a single operand to produce another value. The type of
1631
/// the operand and the result are not necessarily the same. Valid operand types
1632
/// depend on the operator itself.
1633
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1634
pub enum UnaryOperator {
1635
    /// Absolute value operator.
1636
    ///
1637
    /// Return the absolute value of the operand, component-wise for vectors.
1638
    /// Only valid for numeric operands.
1639
    Abs,
1640

1641
    /// Logical ALL operator for bool vectors.
1642
    ///
1643
    /// Return `true` if all the components of the bool vector operand are
1644
    /// `true`. Invalid for any other type of operand.
1645
    All,
1646

1647
    /// Logical ANY operator for bool vectors.
1648
    ///
1649
    /// Return `true` if any component of the bool vector operand is `true`.
1650
    /// Invalid for any other type of operand.
1651
    Any,
1652

1653
    /// Ceiling operator.
1654
    ///
1655
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1656
    /// `x` is the operand which the operator applies to.
1657
    Ceil,
1658

1659
    /// Cosine operator.
1660
    Cos,
1661

1662
    /// Natural exponent operator.
1663
    ///
1664
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1665
    /// for vectors.
1666
    Exp,
1667

1668
    /// Base-2 exponent operator.
1669
    ///
1670
    /// Return two raised to the power of the operand (`2^x`), component-wise
1671
    /// for vectors.
1672
    Exp2,
1673

1674
    /// Floor operator.
1675
    ///
1676
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1677
    /// `x` is the operand which the operator applies to.
1678
    Floor,
1679

1680
    /// Fractional part operator.
1681
    ///
1682
    /// Return the fractional part of the operand, which is equal to `x -
1683
    /// floor(x)`, component-wise for vectors.
1684
    Fract,
1685

1686
    /// Inverse square root operator.
1687
    ///
1688
    /// Return the inverse square root of the floating-point operand (`1.0 /
1689
    /// sqrt(x)`), component-wise for vectors.
1690
    InvSqrt,
1691

1692
    /// Length operator.
1693
    ///
1694
    /// Return the length of a floating point scalar or vector. The "length" of
1695
    /// a scalar is taken as its absolute value. The length of a vector is the
1696
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1697
    /// squared components).
1698
    ///
1699
    /// The output is always a floating point scalar.
1700
    Length,
1701

1702
    /// Natural logarithm operator.
1703
    ///
1704
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1705
    /// for vectors.
1706
    Log,
1707

1708
    /// Base-2 logarithm operator.
1709
    ///
1710
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1711
    /// for vectors.
1712
    Log2,
1713

1714
    /// Vector normalizing operator.
1715
    ///
1716
    /// Normalize the given numeric vector. Only valid for numeric vector
1717
    /// operands.
1718
    Normalize,
1719

1720
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1721
    ///
1722
    /// Convert the four components of a signed normalized floating point vector
1723
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1724
    /// four values into a single `u32`. Each vector component should be in
1725
    /// `[-1:1]` before packing; values outside this range are clamped.
1726
    Pack4x8snorm,
1727

1728
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1729
    ///
1730
    /// Convert the four components of an unsigned normalized floating point
1731
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1732
    /// those four values into a single `u32`. Each vector component should
1733
    /// be in `[0:1]` before packing; values outside this range are clamped.
1734
    Pack4x8unorm,
1735

1736
    /// Saturate operator.
1737
    ///
1738
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1739
    /// vectors.
1740
    Saturate,
1741

1742
    /// Sign operator.
1743
    ///
1744
    /// Return a value representing the sign of a floating point scalar or
1745
    /// vector input:
1746
    /// - `1.` if the operand is > 0
1747
    /// - `0.` if the operand is = 0
1748
    /// - `-1.` if the operand is < 0
1749
    ///
1750
    /// Applies component-wise for vectors.
1751
    Sign,
1752

1753
    /// Sine operator.
1754
    Sin,
1755

1756
    /// Square root operator.
1757
    ///
1758
    /// Return the square root of the floating-point operand, component-wise for
1759
    /// vectors.
1760
    Sqrt,
1761

1762
    /// Tangent operator.
1763
    Tan,
1764

1765
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1766
    ///
1767
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1768
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1769
    Unpack4x8snorm,
1770

1771
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1772
    ///
1773
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1774
    /// then convert each value to an unsigned normalized `f32` value in
1775
    /// `[0:1]`.
1776
    Unpack4x8unorm,
1777

1778
    /// Get the fourth component of a vector.
1779
    ///
1780
    /// This is only valid for vectors of rank 4.
1781
    W,
1782

1783
    /// Get the first component of a scalar or vector.
1784
    ///
1785
    /// For scalar, return the value itself. For vectors, return the first
1786
    /// component.
1787
    X,
1788

1789
    /// Get the second component of a vector.
1790
    Y,
1791

1792
    /// Get the third component of a vector.
1793
    ///
1794
    /// This is only valid for vectors of rank 3 or more.
1795
    Z,
1796
}
1797

1798
impl UnaryOperator {
1799
    /// Check if a unary operator is called via a functional-style call.
1800
    ///
1801
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
1802
    /// example, while non-functional ones are in the form `inner.op`,
1803
    /// like `v.x` for example. This check is used for formatting the WGSL
1804
    /// code emitted during evaluation of a binary operation expression.
1805
    pub fn is_functional(&self) -> bool {
34✔
1806
        !matches!(
30✔
1807
            *self,
34✔
1808
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
1809
        )
1810
    }
1811
}
1812

1813
impl ToWgslString for UnaryOperator {
1814
    fn to_wgsl_string(&self) -> String {
34✔
1815
        match *self {
34✔
1816
            UnaryOperator::Abs => "abs".to_string(),
5✔
1817
            UnaryOperator::All => "all".to_string(),
1✔
1818
            UnaryOperator::Any => "any".to_string(),
3✔
1819
            UnaryOperator::Ceil => "ceil".to_string(),
1✔
1820
            UnaryOperator::Cos => "cos".to_string(),
1✔
1821
            UnaryOperator::Exp => "exp".to_string(),
1✔
1822
            UnaryOperator::Exp2 => "exp2".to_string(),
1✔
1823
            UnaryOperator::Floor => "floor".to_string(),
1✔
1824
            UnaryOperator::Fract => "fract".to_string(),
1✔
1825
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
1✔
1826
            UnaryOperator::Length => "length".to_string(),
1✔
1827
            UnaryOperator::Log => "log".to_string(),
1✔
1828
            UnaryOperator::Log2 => "log2".to_string(),
1✔
1829
            UnaryOperator::Normalize => "normalize".to_string(),
2✔
1830
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
1✔
1831
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
1✔
1832
            UnaryOperator::Saturate => "saturate".to_string(),
1✔
1833
            UnaryOperator::Sign => "sign".to_string(),
1✔
1834
            UnaryOperator::Sin => "sin".to_string(),
1✔
1835
            UnaryOperator::Sqrt => "sqrt".to_string(),
1✔
1836
            UnaryOperator::Tan => "tan".to_string(),
1✔
1837
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
1✔
1838
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
1✔
1839
            UnaryOperator::W => "w".to_string(),
1✔
1840
            UnaryOperator::X => "x".to_string(),
1✔
1841
            UnaryOperator::Y => "y".to_string(),
1✔
1842
            UnaryOperator::Z => "z".to_string(),
1✔
1843
        }
1844
    }
1845
}
1846

1847
/// Binary operator.
1848
///
1849
/// Operator applied between two operands, generally denoted "left" and "right".
1850
/// The type of the operands and the result are not necessarily the same. Valid
1851
/// operand types depend on the operator itself.
1852
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1853
pub enum BinaryOperator {
1854
    /// Addition operator.
1855
    ///
1856
    /// Returns the sum of its operands. Only valid for numeric operands.
1857
    Add,
1858

1859
    /// Cross product operator.
1860
    ///
1861
    /// Returns the cross product of the left and right operands. Only valid for
1862
    /// vector type operands of size 3. Always produce a vector result of the
1863
    /// same size.
1864
    Cross,
1865

1866
    /// Distance operator.
1867
    ///
1868
    /// Returns the distance between two floating point scalar or vectors, that
1869
    /// is `length(right - left)`.
1870
    Distance,
1871

1872
    /// Division operator.
1873
    ///
1874
    /// Returns the left operand divided by the right operand. Only valid for
1875
    /// numeric operands.
1876
    Div,
1877

1878
    /// Dot product operator.
1879
    ///
1880
    /// Returns the dot product of the left and right operands. Only valid for
1881
    /// vector type operands. Always produce a scalar floating-point result.
1882
    Dot,
1883

1884
    /// Greater-than operator.
1885
    ///
1886
    /// Returns `true` if the left operand is strictly greater than the right
1887
    /// operand. Only valid for numeric types. If the operands are vectors,
1888
    /// they must be of the same rank, and the result is a bool vector of
1889
    /// that rank.
1890
    GreaterThan,
1891

1892
    /// Greater-than-or-equal operator.
1893
    ///
1894
    /// Returns `true` if the left operand is greater than or equal to the right
1895
    /// operand. Only valid for numeric types. If the operands are vectors,
1896
    /// they must be of the same rank, and the result is a bool vector of
1897
    /// that rank.
1898
    GreaterThanOrEqual,
1899

1900
    /// Less-than operator.
1901
    ///
1902
    /// Returns `true` if the left operand is strictly less than the right
1903
    /// operand. Only valid for numeric types. If the operands are vectors,
1904
    /// they must be of the same rank, and the result is a bool vector of
1905
    /// that rank.
1906
    LessThan,
1907

1908
    /// Less-than-or-equal operator.
1909
    ///
1910
    /// Returns `true` if the left operand is less than or equal to the right
1911
    /// operand. Only valid for numeric types. If the operands are vectors,
1912
    /// they must be of the same rank, and the result is a bool vector of
1913
    /// that rank.
1914
    LessThanOrEqual,
1915

1916
    /// Maximum operator.
1917
    ///
1918
    /// Returns the maximum value of its left and right operands. Only valid for
1919
    /// numeric types. If the operands are vectors, they must be of the same
1920
    /// rank, and the result is a vector of that rank and same element
1921
    /// scalar type.
1922
    Max,
1923

1924
    /// Minimum operator.
1925
    ///
1926
    /// Returns the minimum value of its left and right operands. Only valid for
1927
    /// numeric types. If the operands are vectors, they must be of the same
1928
    /// rank, and the result is a vector of that rank and same element
1929
    /// scalar type.
1930
    Min,
1931

1932
    /// Multiply operator.
1933
    ///
1934
    /// Returns the product of its operands. Only valid for numeric operands.
1935
    Mul,
1936

1937
    /// Remainder operator.
1938
    ///
1939
    /// Returns the remainder of the division of the first operand by the
1940
    /// second. Only valid for numeric types. If the operands are vectors,
1941
    /// they must be of the same rank, and the result is a vector of that
1942
    /// rank and same element scalar type.
1943
    Remainder,
1944

1945
    /// Stepping operator.
1946
    ///
1947
    /// Returns `1.0` if the left operand is less than or equal to the right
1948
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
1949
    /// of the same rank, and applied component-wise for vectors.
1950
    Step,
1951

1952
    /// Subtraction operator.
1953
    ///
1954
    /// Returns the difference between its left and right operands. Only valid
1955
    /// for numeric operands.
1956
    Sub,
1957

1958
    /// Uniform random number operator.
1959
    ///
1960
    /// Returns a value generated by a fast non-cryptographically-secure
1961
    /// pseudo-random number generator (PRNG) whose statistical characteristics
1962
    /// are undefined and generally focused around speed. The random value is
1963
    /// uniformly distributed between the left and right operands, which must be
1964
    /// numeric types. If the operands are vectors, they must be of the same
1965
    /// rank, and the result is a vector of that rank and same element
1966
    /// scalar type.
1967
    UniformRand,
1968

1969
    /// Normal distribution random number operator.
1970
    ///
1971
    /// Returns a value generated by a fast non-cryptographically-secure
1972
    /// pseudo-random number generator (PRNG) whose statistical characteristics
1973
    /// are undefined and generally focused around speed. The random value is
1974
    /// normally distributed with mean given by the first operand and standard
1975
    /// deviation by the second, which must be numeric types. If the operands
1976
    /// are vectors, they must be of the same rank, and the result is a vector
1977
    /// of that rank and same element scalar type.
1978
    NormalRand,
1979

1980
    /// Constructor for 2-element vectors.
1981
    ///
1982
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
1983
    /// those two elements `(x, y)`.
1984
    Vec2,
1985
}
1986

1987
impl BinaryOperator {
1988
    /// Check if a binary operator is called via a functional-style call.
1989
    ///
1990
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
1991
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
1992
    /// like `a + b` for example. This check is used for formatting the WGSL
1993
    /// code emitted during evaluation of a binary operation expression.
1994
    pub fn is_functional(&self) -> bool {
38✔
1995
        match *self {
38✔
1996
            BinaryOperator::Add
1997
            | BinaryOperator::Div
1998
            | BinaryOperator::GreaterThan
1999
            | BinaryOperator::GreaterThanOrEqual
2000
            | BinaryOperator::LessThan
2001
            | BinaryOperator::LessThanOrEqual
2002
            | BinaryOperator::Mul
2003
            | BinaryOperator::Remainder
2004
            | BinaryOperator::Sub => false,
27✔
2005
            BinaryOperator::Cross
2006
            | BinaryOperator::Distance
2007
            | BinaryOperator::Dot
2008
            | BinaryOperator::Max
2009
            | BinaryOperator::Min
2010
            | BinaryOperator::Step
2011
            | BinaryOperator::UniformRand
2012
            | BinaryOperator::NormalRand
2013
            | BinaryOperator::Vec2 => true,
11✔
2014
        }
2015
    }
2016

2017
    /// Check if a binary operator needs a type suffix.
2018
    ///
2019
    /// This is currently just for `rand_uniform`
2020
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2021
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2022
    /// WGSL doesn't support user-defined function overloading, so we need a
2023
    /// suffix to disambiguate the types.
2024
    pub fn needs_type_suffix(&self) -> bool {
11✔
2025
        matches!(
11✔
2026
            *self,
11✔
2027
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2028
        )
2029
    }
2030
}
2031

2032
impl ToWgslString for BinaryOperator {
2033
    fn to_wgsl_string(&self) -> String {
38✔
2034
        match *self {
38✔
2035
            BinaryOperator::Add => "+".to_string(),
5✔
2036
            BinaryOperator::Cross => "cross".to_string(),
1✔
2037
            BinaryOperator::Distance => "distance".to_string(),
1✔
2038
            BinaryOperator::Div => "/".to_string(),
2✔
2039
            BinaryOperator::Dot => "dot".to_string(),
1✔
2040
            BinaryOperator::GreaterThan => ">".to_string(),
3✔
2041
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
1✔
2042
            BinaryOperator::LessThan => "<".to_string(),
1✔
2043
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
1✔
2044
            BinaryOperator::Max => "max".to_string(),
5✔
2045
            BinaryOperator::Min => "min".to_string(),
2✔
2046
            BinaryOperator::Mul => "*".to_string(),
6✔
2047
            BinaryOperator::Remainder => "%".to_string(),
1✔
2048
            BinaryOperator::Step => "step".to_string(),
1✔
2049
            BinaryOperator::Sub => "-".to_string(),
7✔
2050
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
2051
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
2052
            BinaryOperator::Vec2 => "vec2".to_string(),
×
2053
        }
2054
    }
2055
}
2056

2057
/// Ternary operator.
2058
///
2059
/// Operator applied between three operands. The type of the operands and the
2060
/// result are not necessarily the same. Valid operand types depend on the
2061
/// operator itself.
2062
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2063
pub enum TernaryOperator {
2064
    /// Linear blend ("mix") operator.
2065
    ///
2066
    /// Returns the linear blend between the first and second argument, based on
2067
    /// the fraction of the third argument. If the operands are vectors, they
2068
    /// must be of the same rank, and the result is a vector of that rank
2069
    /// and same element scalar type.
2070
    ///
2071
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2072
    /// (1 - t) + y * t`.
2073
    Mix,
2074

2075
    /// Smooth stepping operator.
2076
    ///
2077
    /// Returns the smooth Hermitian interpolation between the first and second
2078
    /// argument, calculated at the third argument. If the operands are vectors,
2079
    /// they must be of the same rank, and the result is a vector of that
2080
    /// rank and same element scalar type.
2081
    ///
2082
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2083
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2084
    /// represents the fractional position of `x` between `low` and `high`.
2085
    ///
2086
    /// The result is always a floating point scalar in \[0:1\].
2087
    SmoothStep,
2088

2089
    /// Constructor for 3-element vectors.
2090
    ///
2091
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2092
    /// consisting of those three elements `(x, y, z)`.
2093
    Vec3,
2094
}
2095

2096
impl ToWgslString for TernaryOperator {
2097
    fn to_wgsl_string(&self) -> String {
3✔
2098
        match *self {
3✔
2099
            TernaryOperator::Mix => "mix".to_string(),
2✔
2100
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
1✔
2101
            TernaryOperator::Vec3 => "vec3".to_string(),
×
2102
        }
2103
    }
2104
}
2105

2106
/// Expression writer.
2107
///
2108
/// Utility to write expressions with a simple functional syntax. Expressions
2109
/// created with the writer are gatherned into a [`Module`] which can be
2110
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2111
///
2112
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2113
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2114
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2115
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2116
/// to assign it to the [`EffectAsset`].
2117
///
2118
/// # Example
2119
///
2120
/// ```
2121
/// # use bevy_hanabi::*;
2122
/// # use bevy::prelude::*;
2123
/// // Create a writer
2124
/// let w = ExprWriter::new();
2125
///
2126
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2127
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2128
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2129
///
2130
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2131
/// let expr: ExprHandle = expr.expr();
2132
///
2133
/// // Create a modifier and assign the expression to one of its input(s)
2134
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2135
///
2136
/// // Create an EffectAsset with the modifier and the Module from the writer
2137
/// let effect =
2138
///     EffectAsset::new(1024, Spawner::rate(32_f32.into()), w.finish()).init(init_modifier);
2139
/// ```
2140
///
2141
/// [`finish()`]: ExprWriter::finish
2142
/// [`EffectAsset`]: crate::EffectAsset
2143
/// [`Modifer`]: crate::Modifier
2144
#[derive(Debug, Default, Clone)]
2145
pub struct ExprWriter {
2146
    module: Rc<RefCell<Module>>,
2147
}
2148

2149
#[allow(dead_code)]
2150
impl ExprWriter {
2151
    /// Create a new writer.
2152
    ///
2153
    /// The writer owns a new [`Module`] internally, and write all expressions
2154
    /// to it. The module can be released to the user with [`finish()`] once
2155
    /// done using the writer.
2156
    ///
2157
    /// [`finish()`]: ExprWriter::finish
2158
    pub fn new() -> Self {
3✔
2159
        Self {
2160
            module: Rc::new(RefCell::new(Module::default())),
3✔
2161
        }
2162
    }
2163

2164
    /// Create a new writer from an existing module.
2165
    ///
2166
    /// This is an advanced use entry point to write expressions into an
2167
    /// existing [`Module`]. In general, users should prefer using
2168
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2169
    /// same [`ExprWriter`] to write all expressions of the same
2170
    /// [`EffectAsset`].
2171
    ///
2172
    /// [`EffectAsset`]: crate::EffectAsset
2173
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2174
        Self { module }
2175
    }
2176

2177
    /// Add a new property.
2178
    ///
2179
    /// See [`Property`] for more details on what effect properties are.
2180
    ///
2181
    /// # Panics
2182
    ///
2183
    /// Panics if a property with the same name already exists.
2184
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2185
        self.module.borrow_mut().add_property(name, default_value)
1✔
2186
    }
2187

2188
    /// Push a new expression into the writer.
2189
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2190
        let expr = {
13✔
2191
            let mut m = self.module.borrow_mut();
13✔
2192
            m.push(expr.into())
13✔
2193
        };
2194
        WriterExpr {
2195
            expr,
2196
            module: Rc::clone(&self.module),
13✔
2197
        }
2198
    }
2199

2200
    /// Create a new writer expression from a literal constant.
2201
    ///
2202
    /// # Example
2203
    ///
2204
    /// ```
2205
    /// # use bevy_hanabi::*;
2206
    /// let mut w = ExprWriter::new();
2207
    /// let x = w.lit(-3.5); // x = -3.5;
2208
    /// ```
2209
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2210
        self.push(Expr::Literal(LiteralExpr {
11✔
2211
            value: value.into(),
11✔
2212
        }))
2213
    }
2214

2215
    /// Create a new writer expression from an attribute.
2216
    ///
2217
    /// # Example
2218
    ///
2219
    /// ```
2220
    /// # use bevy_hanabi::*;
2221
    /// let mut w = ExprWriter::new();
2222
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2223
    /// ```
2224
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2225
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
1✔
2226
    }
2227

2228
    /// Create a new writer expression from a property.
2229
    ///
2230
    /// # Example
2231
    ///
2232
    /// ```
2233
    /// # use bevy_hanabi::*;
2234
    /// let mut w = ExprWriter::new();
2235
    /// let prop = w.add_property("my_prop", 3.0.into());
2236
    /// let x = w.prop(prop); // x = properties.my_prop;
2237
    /// ```
2238
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2239
        self.push(Expr::Property(PropertyExpr::new(handle)))
1✔
2240
    }
2241

2242
    /// Create a new writer expression representing the current simulation time.
2243
    ///
2244
    /// # Example
2245
    ///
2246
    /// ```
2247
    /// # use bevy_hanabi::*;
2248
    /// let mut w = ExprWriter::new();
2249
    /// let x = w.time(); // x = sim_params.time;
2250
    /// ```
2251
    pub fn time(&self) -> WriterExpr {
×
2252
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2253
    }
2254

2255
    /// Create a new writer expression representing the simulation delta time
2256
    /// since last frame.
2257
    ///
2258
    /// # Example
2259
    ///
2260
    /// ```
2261
    /// # use bevy_hanabi::*;
2262
    /// let mut w = ExprWriter::new();
2263
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2264
    /// ```
2265
    pub fn delta_time(&self) -> WriterExpr {
×
2266
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2267
    }
2268

2269
    /// Create a new writer expression representing a random value of the given
2270
    /// type.
2271
    ///
2272
    /// The type can be any scalar or vector type. Matrix types are not
2273
    /// supported. The random values generated are uniformly distributed in
2274
    /// `[0:1]`. For vectors, each component is sampled separately.
2275
    ///
2276
    /// # Panics
2277
    ///
2278
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2279
    ///
2280
    /// # Example
2281
    ///
2282
    /// ```
2283
    /// # use bevy_hanabi::*;
2284
    /// let mut w = ExprWriter::new();
2285
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2286
    /// ```
2287
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2288
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2289
            value_type.into(),
×
2290
        ))))
2291
    }
2292

2293
    /// Create a new writer expression representing the alpha cutoff value used
2294
    /// for alpha masking.
2295
    ///
2296
    /// This expression is only valid when used in the context of the fragment
2297
    /// shader, in the render context.
2298
    ///
2299
    /// # Example
2300
    ///
2301
    /// ```
2302
    /// # use bevy_hanabi::*;
2303
    /// let mut w = ExprWriter::new();
2304
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2305
    /// ```
2306
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2307
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2308
            BuiltInOperator::AlphaCutoff,
×
2309
        )))
2310
    }
2311

2312
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2313
    /// were written by the writer.
2314
    ///
2315
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2316
    /// to that effect the modifiers which use the expressions created by this
2317
    /// writer.
2318
    ///
2319
    /// # Example
2320
    ///
2321
    /// ```
2322
    /// # use bevy_hanabi::*;
2323
    /// # let spawner = Spawner::default();
2324
    /// let mut w = ExprWriter::new();
2325
    /// // [...]
2326
    /// let module = w.finish();
2327
    /// let asset = EffectAsset::new(256, spawner, module);
2328
    /// ```
2329
    ///
2330
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2331
    pub fn finish(self) -> Module {
3✔
2332
        self.module.take()
3✔
2333
    }
2334
}
2335

2336
/// Intermediate expression from an [`ExprWriter`].
2337
///
2338
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2339
/// retains a reference to the underlying [`Module`] and therefore can easily be
2340
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2341
/// being more heavyweight and locking the underlying [`Module`] under a
2342
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2343
/// opposition is a very lightweight type, similar to a simple index. And like
2344
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2345
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2346
///
2347
/// In addition, [`WriterExpr`] implements several numerical operators like the
2348
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2349
/// [`WriterExpr`].
2350
///
2351
/// ```
2352
/// # use bevy_hanabi::*;
2353
/// let mut w = ExprWriter::new();
2354
/// let x = w.lit(-3.5);
2355
/// let y = w.lit(78.);
2356
/// let z = x + y; // == 74.5
2357
/// ```
2358
///
2359
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2360
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2361
///
2362
/// ```
2363
/// # use bevy_hanabi::*;
2364
/// let mut w = ExprWriter::new();
2365
/// let my_prop = w.add_property("my_prop", 3.0.into());
2366
///
2367
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2368
/// let x = (w.lit(-3.5) + w.lit(1.))
2369
///     .max(w.prop(my_prop))
2370
///     .mul(w.lit(0.5))
2371
///     .sub(w.attr(Attribute::POSITION));
2372
///
2373
/// let handle: ExprHandle = x.expr();
2374
/// ```
2375
#[derive(Debug, Clone)]
2376
pub struct WriterExpr {
2377
    expr: ExprHandle,
2378
    module: Rc<RefCell<Module>>,
2379
}
2380

2381
impl WriterExpr {
2382
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2383
        let expr = self.module.borrow_mut().push(Expr::Unary {
1✔
2384
            op,
1✔
2385
            expr: self.expr,
1✔
2386
        });
2387
        WriterExpr {
2388
            expr,
2389
            module: self.module,
1✔
2390
        }
2391
    }
2392

2393
    /// Take the absolute value of the current expression.
2394
    ///
2395
    /// This is a unary operator, which applies component-wise to vector and
2396
    /// matrix operand expressions.
2397
    ///
2398
    /// # Example
2399
    ///
2400
    /// ```
2401
    /// # use bevy_hanabi::*;
2402
    /// # let mut w = ExprWriter::new();
2403
    /// // A literal expression `x = -3.5;`.
2404
    /// let x = w.lit(-3.5);
2405
    ///
2406
    /// // The absolute value `y = abs(x);`.
2407
    /// let y = x.abs(); // == 3.5
2408
    /// ```
2409
    #[inline]
2410
    pub fn abs(self) -> Self {
1✔
2411
        self.unary_op(UnaryOperator::Abs)
1✔
2412
    }
2413

2414
    /// Apply the logical operator "all" to the current bool vector expression.
2415
    ///
2416
    /// This is a unary operator, which applies to vector operand expressions to
2417
    /// produce a scalar boolean.
2418
    ///
2419
    /// # Example
2420
    ///
2421
    /// ```
2422
    /// # use bevy_hanabi::*;
2423
    /// # use bevy::math::BVec3;
2424
    /// # let mut w = ExprWriter::new();
2425
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2426
    /// let x = w.lit(BVec3::new(true, false, true));
2427
    ///
2428
    /// // Check if all components are true `y = all(x);`.
2429
    /// let y = x.all(); // == false
2430
    /// ```
2431
    #[inline]
2432
    pub fn all(self) -> Self {
×
2433
        self.unary_op(UnaryOperator::All)
×
2434
    }
2435

2436
    /// Apply the logical operator "any" to the current bool vector expression.
2437
    ///
2438
    /// This is a unary operator, which applies to vector operand expressions to
2439
    /// produce a scalar boolean.
2440
    ///
2441
    /// # Example
2442
    ///
2443
    /// ```
2444
    /// # use bevy_hanabi::*;
2445
    /// # use bevy::math::BVec3;
2446
    /// # let mut w = ExprWriter::new();
2447
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2448
    /// let x = w.lit(BVec3::new(true, false, true));
2449
    ///
2450
    /// // Check if any components is true `y = any(x);`.
2451
    /// let y = x.any(); // == true
2452
    /// ```
2453
    #[inline]
2454
    pub fn any(self) -> Self {
×
2455
        self.unary_op(UnaryOperator::Any)
×
2456
    }
2457

2458
    /// Apply the "ceil" operator to the current float scalar or vector
2459
    /// expression.
2460
    ///
2461
    /// This is a unary operator, which applies to float scalar or vector
2462
    /// operand expressions to produce a float scalar or vector. It applies
2463
    /// component-wise to vector operand expressions.
2464
    ///
2465
    /// # Example
2466
    ///
2467
    /// ```
2468
    /// # use bevy_hanabi::*;
2469
    /// # use bevy::math::Vec3;
2470
    /// # let mut w = ExprWriter::new();
2471
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2472
    /// let x = w.lit(Vec3::ONE);
2473
    ///
2474
    /// // Ceil: `y = ceil(x);`
2475
    /// let y = x.ceil();
2476
    /// ```
2477
    #[inline]
2478
    pub fn ceil(self) -> Self {
×
2479
        self.unary_op(UnaryOperator::Ceil)
×
2480
    }
2481

2482
    /// Apply the "cos" operator to the current float scalar or vector
2483
    /// expression.
2484
    ///
2485
    /// This is a unary operator, which applies to float scalar or vector
2486
    /// operand expressions to produce a float scalar or vector. It applies
2487
    /// component-wise to vector operand expressions.
2488
    ///
2489
    /// # Example
2490
    ///
2491
    /// ```
2492
    /// # use bevy_hanabi::*;
2493
    /// # use bevy::math::Vec3;
2494
    /// # let mut w = ExprWriter::new();
2495
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2496
    /// let x = w.lit(Vec3::ONE);
2497
    ///
2498
    /// // Cos: `y = cos(x);`
2499
    /// let y = x.cos();
2500
    /// ```
2501
    #[inline]
2502
    pub fn cos(self) -> Self {
×
2503
        self.unary_op(UnaryOperator::Cos)
×
2504
    }
2505

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

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

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

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

2602
    /// Apply the "inverseSqrt" (inverse square root) operator to the current
2603
    /// float scalar or vector expression.
2604
    ///
2605
    /// This is a unary operator, which applies to float scalar or vector
2606
    /// operand expressions to produce a float scalar or vector. It applies
2607
    /// component-wise to vector operand expressions.
2608
    ///
2609
    /// # Example
2610
    ///
2611
    /// ```
2612
    /// # use bevy_hanabi::*;
2613
    /// # use bevy::math::Vec3;
2614
    /// # let mut w = ExprWriter::new();
2615
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2616
    /// let x = w.lit(Vec3::ONE);
2617
    ///
2618
    /// // Inverse square root: `y = inverseSqrt(x) = 1.0 / sqrt(x);`
2619
    /// let y = x.inverse_sqrt();
2620
    /// ```
2621
    #[inline]
2622
    pub fn inverse_sqrt(self) -> Self {
×
2623
        self.unary_op(UnaryOperator::InvSqrt)
×
2624
    }
2625

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

2650
    /// Apply the "log" operator to the current float scalar or vector
2651
    /// expression.
2652
    ///
2653
    /// This is a unary operator, which applies to float scalar or vector
2654
    /// operand expressions to produce a float scalar or vector. It applies
2655
    /// component-wise to vector operand expressions.
2656
    ///
2657
    /// # Example
2658
    ///
2659
    /// ```
2660
    /// # use bevy_hanabi::*;
2661
    /// # use bevy::math::Vec3;
2662
    /// # let mut w = ExprWriter::new();
2663
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2664
    /// let x = w.lit(Vec3::ONE);
2665
    ///
2666
    /// // Log: `y = log(x);`
2667
    /// let y = x.log();
2668
    /// ```
2669
    #[inline]
2670
    pub fn log(self) -> Self {
×
2671
        self.unary_op(UnaryOperator::Log)
×
2672
    }
2673

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

2698
    /// Apply the "normalize" operator to the current float vector expression.
2699
    ///
2700
    /// This is a unary operator, which applies to float vector operand
2701
    /// expressions to produce another float vector with unit length
2702
    /// (normalized).
2703
    ///
2704
    /// # Example
2705
    ///
2706
    /// ```
2707
    /// # use bevy_hanabi::*;
2708
    /// # use bevy::math::Vec3;
2709
    /// # let mut w = ExprWriter::new();
2710
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2711
    /// let x = w.lit(Vec3::ONE);
2712
    ///
2713
    /// // Normalize: `y = normalize(x);`
2714
    /// let y = x.normalized();
2715
    /// ```
2716
    #[inline]
2717
    pub fn normalized(self) -> Self {
×
2718
        self.unary_op(UnaryOperator::Normalize)
×
2719
    }
2720

2721
    /// Apply the "pack4x8snorm" operator to the current 4-component float
2722
    /// vector expression.
2723
    ///
2724
    /// This is a unary operator, which applies to 4-component float vector
2725
    /// operand expressions to produce a single `u32` scalar expression.
2726
    ///
2727
    /// # Example
2728
    ///
2729
    /// ```
2730
    /// # use bevy_hanabi::*;
2731
    /// # use bevy::math::Vec4;
2732
    /// # let mut w = ExprWriter::new();
2733
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2734
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2735
    ///
2736
    /// // Pack: `y = pack4x8snorm(x);`
2737
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
2738
    /// ```
2739
    #[inline]
2740
    pub fn pack4x8snorm(self) -> Self {
×
2741
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
2742
    }
2743

2744
    /// Apply the "pack4x8unorm" operator to the current 4-component float
2745
    /// vector expression.
2746
    ///
2747
    /// This is a unary operator, which applies to 4-component float vector
2748
    /// operand expressions to produce a single `u32` scalar expression.
2749
    ///
2750
    /// # Example
2751
    ///
2752
    /// ```
2753
    /// # use bevy_hanabi::*;
2754
    /// # use bevy::math::Vec4;
2755
    /// # let mut w = ExprWriter::new();
2756
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2757
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2758
    ///
2759
    /// // Pack: `y = pack4x8unorm(x);`
2760
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
2761
    /// ```
2762
    #[inline]
2763
    pub fn pack4x8unorm(self) -> Self {
×
2764
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
2765
    }
2766

2767
    /// Apply the "sign" operator to the current float scalar or vector
2768
    /// expression.
2769
    ///
2770
    /// This is a unary operator, which applies to float scalar or vector
2771
    /// operand expressions to produce a float scalar or vector. It applies
2772
    /// component-wise to vector operand expressions.
2773
    ///
2774
    /// # Example
2775
    ///
2776
    /// ```
2777
    /// # use bevy_hanabi::*;
2778
    /// # use bevy::math::Vec3;
2779
    /// # let mut w = ExprWriter::new();
2780
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2781
    /// let x = w.lit(Vec3::ONE);
2782
    ///
2783
    /// // Sign: `y = sign(x);`
2784
    /// let y = x.sign();
2785
    /// ```
2786
    #[inline]
2787
    pub fn sign(self) -> Self {
×
2788
        self.unary_op(UnaryOperator::Sign)
×
2789
    }
2790

2791
    /// Apply the "sin" operator to the current float scalar or vector
2792
    /// expression.
2793
    ///
2794
    /// This is a unary operator, which applies to float scalar or vector
2795
    /// operand expressions to produce a float scalar or vector. It applies
2796
    /// component-wise to vector operand expressions.
2797
    ///
2798
    /// # Example
2799
    ///
2800
    /// ```
2801
    /// # use bevy_hanabi::*;
2802
    /// # use bevy::math::Vec3;
2803
    /// # let mut w = ExprWriter::new();
2804
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2805
    /// let x = w.lit(Vec3::ONE);
2806
    ///
2807
    /// // Sin: `y = sin(x);`
2808
    /// let y = x.sin();
2809
    /// ```
2810
    #[inline]
2811
    pub fn sin(self) -> Self {
×
2812
        self.unary_op(UnaryOperator::Sin)
×
2813
    }
2814

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

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

2863
    /// Apply the "unpack4x8snorm" operator to the current `u32` scalar
2864
    /// expression.
2865
    ///
2866
    /// This is a unary operator, which applies to `u32` scalar operand
2867
    /// expressions to produce a 4-component floating point vector of signed
2868
    /// normalized components in `[-1:1]`.
2869
    ///
2870
    /// # Example
2871
    ///
2872
    /// ```
2873
    /// # use bevy_hanabi::*;
2874
    /// # use bevy::math::Vec3;
2875
    /// # let mut w = ExprWriter::new();
2876
    /// // A literal expression `y = 0x7F007FFFu32;`.
2877
    /// let y = w.lit(0x7F007FFFu32);
2878
    ///
2879
    /// // Unpack: `x = unpack4x8snorm(y);`
2880
    /// let x = y.unpack4x8snorm(); // vec4<f32>(-1., 1., 0., 7.2)
2881
    /// ```
2882
    #[inline]
2883
    pub fn unpack4x8snorm(self) -> Self {
×
2884
        self.unary_op(UnaryOperator::Unpack4x8snorm)
×
2885
    }
2886

2887
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
2888
    /// expression.
2889
    ///
2890
    /// This is a unary operator, which applies to `u32` scalar operand
2891
    /// expressions to produce a 4-component floating point vector of unsigned
2892
    /// normalized components in `[0:1]`.
2893
    ///
2894
    /// # Example
2895
    ///
2896
    /// ```
2897
    /// # use bevy_hanabi::*;
2898
    /// # use bevy::math::Vec3;
2899
    /// # let mut w = ExprWriter::new();
2900
    /// // A literal expression `y = 0xFF00FF00u32;`.
2901
    /// let y = w.lit(0xFF00FF00u32);
2902
    ///
2903
    /// // Unpack: `x = unpack4x8unorm(y);`
2904
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
2905
    /// ```
2906
    #[inline]
2907
    pub fn unpack4x8unorm(self) -> Self {
×
2908
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
2909
    }
2910

2911
    /// Apply the "saturate" operator to the current float scalar or vector
2912
    /// expression.
2913
    ///
2914
    /// This is a unary operator, which applies to float scalar or vector
2915
    /// operand expressions to produce a float scalar or vector. It applies
2916
    /// component-wise to vector operand expressions.
2917
    ///
2918
    /// # Example
2919
    ///
2920
    /// ```
2921
    /// # use bevy_hanabi::*;
2922
    /// # use bevy::math::Vec3;
2923
    /// # let mut w = ExprWriter::new();
2924
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2925
    /// let x = w.lit(Vec3::ONE);
2926
    ///
2927
    /// // Saturate: `y = saturate(x);`
2928
    /// let y = x.saturate();
2929
    /// ```
2930
    #[inline]
2931
    pub fn saturate(self) -> Self {
×
2932
        self.unary_op(UnaryOperator::Saturate)
×
2933
    }
2934

2935
    /// Get the first component of a scalar or vector.
2936
    ///
2937
    /// # Example
2938
    ///
2939
    /// ```
2940
    /// # use bevy_hanabi::*;
2941
    /// # use bevy::math::Vec3;
2942
    /// # let mut w = ExprWriter::new();
2943
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2944
    /// let v = w.lit(Vec3::ONE);
2945
    ///
2946
    /// // f = v.x;`
2947
    /// let f = v.x();
2948
    /// ```
2949
    #[inline]
2950
    pub fn x(self) -> Self {
×
2951
        self.unary_op(UnaryOperator::X)
×
2952
    }
2953

2954
    /// Get the second component of a vector.
2955
    ///
2956
    /// # Example
2957
    ///
2958
    /// ```
2959
    /// # use bevy_hanabi::*;
2960
    /// # use bevy::math::Vec3;
2961
    /// # let mut w = ExprWriter::new();
2962
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2963
    /// let v = w.lit(Vec3::ONE);
2964
    ///
2965
    /// // f = v.y;`
2966
    /// let f = v.y();
2967
    /// ```
2968
    #[inline]
2969
    pub fn y(self) -> Self {
×
2970
        self.unary_op(UnaryOperator::Y)
×
2971
    }
2972

2973
    /// Get the third component of a vector.
2974
    ///
2975
    /// # Example
2976
    ///
2977
    /// ```
2978
    /// # use bevy_hanabi::*;
2979
    /// # use bevy::math::Vec3;
2980
    /// # let mut w = ExprWriter::new();
2981
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2982
    /// let v = w.lit(Vec3::ONE);
2983
    ///
2984
    /// // f = v.z;`
2985
    /// let f = v.z();
2986
    /// ```
2987
    #[inline]
2988
    pub fn z(self) -> Self {
×
2989
        self.unary_op(UnaryOperator::Z)
×
2990
    }
2991

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

3011
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
3012
        assert_eq!(self.module, other.module);
5✔
3013
        let left = self.expr;
5✔
3014
        let right = other.expr;
5✔
3015
        let expr = self
5✔
3016
            .module
5✔
3017
            .borrow_mut()
3018
            .push(Expr::Binary { op, left, right });
5✔
3019
        WriterExpr {
3020
            expr,
3021
            module: self.module,
5✔
3022
        }
3023
    }
3024

3025
    /// Add the current expression with another expression.
3026
    ///
3027
    /// This is a binary operator, which applies component-wise to vector
3028
    /// operand expressions.
3029
    ///
3030
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3031
    /// symbol, as an alternative to calling this method directly.
3032
    ///
3033
    /// # Example
3034
    ///
3035
    /// ```
3036
    /// # use bevy_hanabi::*;
3037
    /// # use bevy::math::Vec2;
3038
    /// # let mut w = ExprWriter::new();
3039
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3040
    /// let x = w.lit(Vec2::new(3., -2.));
3041
    ///
3042
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3043
    /// let y = w.lit(Vec2::new(1., 5.));
3044
    ///
3045
    /// // The sum of both vectors `z = x + y;`.
3046
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3047
    ///                   // -OR-
3048
    ///                   // let z = x + y;
3049
    /// ```
3050
    #[allow(clippy::should_implement_trait)]
3051
    #[inline]
3052
    pub fn add(self, other: Self) -> Self {
2✔
3053
        self.binary_op(other, BinaryOperator::Add)
2✔
3054
    }
3055

3056
    /// Calculate the cross product of the current expression by another
3057
    /// expression.
3058
    ///
3059
    /// This is a binary operator, which applies to vector operands of size 3
3060
    /// only, and always produces a vector of the same size.
3061
    ///
3062
    /// # Example
3063
    ///
3064
    /// ```
3065
    /// # use bevy_hanabi::*;
3066
    /// # use bevy::math::Vec3;
3067
    /// # let mut w = ExprWriter::new();
3068
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3069
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3070
    ///
3071
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3072
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3073
    ///
3074
    /// // The cross product of both vectors `z = cross(x, y);`.
3075
    /// let z = x.cross(y);
3076
    /// ```
3077
    #[inline]
3078
    pub fn cross(self, other: Self) -> Self {
×
3079
        self.binary_op(other, BinaryOperator::Cross)
×
3080
    }
3081

3082
    /// Calculate the dot product of the current expression by another
3083
    /// expression.
3084
    ///
3085
    /// This is a binary operator, which applies to vector operands of same size
3086
    /// only, and always produces a floating point scalar.
3087
    ///
3088
    /// # Example
3089
    ///
3090
    /// ```
3091
    /// # use bevy_hanabi::*;
3092
    /// # use bevy::math::Vec2;
3093
    /// # let mut w = ExprWriter::new();
3094
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3095
    /// let x = w.lit(Vec2::new(3., -2.));
3096
    ///
3097
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3098
    /// let y = w.lit(Vec2::new(1., 5.));
3099
    ///
3100
    /// // The dot product of both vectors `z = dot(x, y);`.
3101
    /// let z = x.dot(y);
3102
    /// ```
3103
    #[inline]
3104
    pub fn dot(self, other: Self) -> Self {
×
3105
        self.binary_op(other, BinaryOperator::Dot)
×
3106
    }
3107

3108
    /// Calculate the distance between the current expression and another
3109
    /// expression.
3110
    ///
3111
    /// This is a binary operator.
3112
    ///
3113
    /// # Example
3114
    ///
3115
    /// ```
3116
    /// # use bevy_hanabi::*;
3117
    /// # use bevy::math::Vec3;
3118
    /// # let mut w = ExprWriter::new();
3119
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3120
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3121
    ///
3122
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3123
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3124
    ///
3125
    /// // The distance between the vectors `z = distance(x, y);`.
3126
    /// let z = x.distance(y);
3127
    /// ```
3128
    #[inline]
3129
    pub fn distance(self, other: Self) -> Self {
×
3130
        self.binary_op(other, BinaryOperator::Distance)
×
3131
    }
3132

3133
    /// Divide the current expression by another expression.
3134
    ///
3135
    /// This is a binary operator, which applies component-wise to vector
3136
    /// operand expressions.
3137
    ///
3138
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3139
    /// symbol, as an alternative to calling this method directly.
3140
    ///
3141
    /// # Example
3142
    ///
3143
    /// ```
3144
    /// # use bevy_hanabi::*;
3145
    /// # use bevy::math::Vec2;
3146
    /// # let mut w = ExprWriter::new();
3147
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3148
    /// let x = w.lit(Vec2::new(3., -2.));
3149
    ///
3150
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3151
    /// let y = w.lit(Vec2::new(1., 5.));
3152
    ///
3153
    /// // The quotient of both vectors `z = x / y;`.
3154
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3155
    ///                   // -OR-
3156
    ///                   // let z = x / y;
3157
    /// ```
3158
    #[allow(clippy::should_implement_trait)]
3159
    #[inline]
3160
    pub fn div(self, other: Self) -> Self {
×
3161
        self.binary_op(other, BinaryOperator::Div)
×
3162
    }
3163

3164
    /// Apply the logical operator "greater than or equal" to this expression
3165
    /// and another expression.
3166
    ///
3167
    /// This is a binary operator, which applies component-wise to vector
3168
    /// operand expressions.
3169
    ///
3170
    /// # Example
3171
    ///
3172
    /// ```
3173
    /// # use bevy_hanabi::*;
3174
    /// # use bevy::math::Vec3;
3175
    /// # let mut w = ExprWriter::new();
3176
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3177
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3178
    ///
3179
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3180
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3181
    ///
3182
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3183
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3184
    /// ```
3185
    #[inline]
3186
    pub fn ge(self, other: Self) -> Self {
×
3187
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3188
    }
3189

3190
    /// Apply the logical operator "greater than" to this expression and another
3191
    /// expression.
3192
    ///
3193
    /// This is a binary operator, which applies component-wise to vector
3194
    /// operand expressions.
3195
    ///
3196
    /// # Example
3197
    ///
3198
    /// ```
3199
    /// # use bevy_hanabi::*;
3200
    /// # use bevy::math::Vec3;
3201
    /// # let mut w = ExprWriter::new();
3202
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3203
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3204
    ///
3205
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3206
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3207
    ///
3208
    /// // The boolean result of the greater than operation `z = (x > y);`.
3209
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3210
    /// ```
3211
    #[inline]
3212
    pub fn gt(self, other: Self) -> Self {
×
3213
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3214
    }
3215

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

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

3268
    /// Take the maximum value of the current expression and another expression.
3269
    ///
3270
    /// This is a binary operator, which applies component-wise to vector
3271
    /// operand expressions.
3272
    ///
3273
    /// # Example
3274
    ///
3275
    /// ```
3276
    /// # use bevy_hanabi::*;
3277
    /// # use bevy::math::Vec2;
3278
    /// # let mut w = ExprWriter::new();
3279
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3280
    /// let x = w.lit(Vec2::new(3., -2.));
3281
    ///
3282
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3283
    /// let y = w.lit(Vec2::new(1., 5.));
3284
    ///
3285
    /// // The maximum of both vectors `z = max(x, y);`.
3286
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3287
    /// ```
3288
    #[inline]
3289
    pub fn max(self, other: Self) -> Self {
1✔
3290
        self.binary_op(other, BinaryOperator::Max)
1✔
3291
    }
3292

3293
    /// Take the minimum value of the current expression and another expression.
3294
    ///
3295
    /// This is a binary operator, which applies component-wise to vector
3296
    /// operand expressions.
3297
    ///
3298
    /// # Example
3299
    ///
3300
    /// ```
3301
    /// # use bevy_hanabi::*;
3302
    /// # use bevy::math::Vec2;
3303
    /// # let mut w = ExprWriter::new();
3304
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3305
    /// let x = w.lit(Vec2::new(3., -2.));
3306
    ///
3307
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3308
    /// let y = w.lit(Vec2::new(1., 5.));
3309
    ///
3310
    /// // The minimum of both vectors `z = min(x, y);`.
3311
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3312
    /// ```
3313
    #[inline]
3314
    pub fn min(self, other: Self) -> Self {
1✔
3315
        self.binary_op(other, BinaryOperator::Min)
1✔
3316
    }
3317

3318
    /// Multiply the current expression with another expression.
3319
    ///
3320
    /// This is a binary operator, which applies component-wise to vector
3321
    /// operand expressions.
3322
    ///
3323
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3324
    /// symbol, as an alternative to calling this method directly.
3325
    ///
3326
    /// # Example
3327
    ///
3328
    /// ```
3329
    /// # use bevy_hanabi::*;
3330
    /// # use bevy::math::Vec2;
3331
    /// # let mut w = ExprWriter::new();
3332
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3333
    /// let x = w.lit(Vec2::new(3., -2.));
3334
    ///
3335
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3336
    /// let y = w.lit(Vec2::new(1., 5.));
3337
    ///
3338
    /// // The product of both vectors `z = x * y;`.
3339
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3340
    ///                   // -OR-
3341
    ///                   // let z = x * y;
3342
    /// ```
3343
    #[allow(clippy::should_implement_trait)]
3344
    #[inline]
3345
    pub fn mul(self, other: Self) -> Self {
1✔
3346
        self.binary_op(other, BinaryOperator::Mul)
1✔
3347
    }
3348

3349
    /// Calculate the remainder of the division of the current expression by
3350
    /// another expression.
3351
    ///
3352
    /// This is a binary operator.
3353
    ///
3354
    /// # Example
3355
    ///
3356
    /// ```
3357
    /// # use bevy_hanabi::*;
3358
    /// # use bevy::math::Vec3;
3359
    /// # let mut w = ExprWriter::new();
3360
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3361
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3362
    ///
3363
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3364
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3365
    ///
3366
    /// // The remainder of the division `z = x % y;`.
3367
    /// let z = x.rem(y);
3368
    /// ```
3369
    #[allow(clippy::should_implement_trait)]
3370
    #[inline]
3371
    pub fn rem(self, other: Self) -> Self {
×
3372
        self.binary_op(other, BinaryOperator::Remainder)
×
3373
    }
3374

3375
    /// Calculate the step of a value with respect to a reference.
3376
    ///
3377
    /// This is a binary operator, which applies component-wise to vector
3378
    /// operand expressions.
3379
    ///
3380
    /// # Example
3381
    ///
3382
    /// ```
3383
    /// # use bevy_hanabi::*;
3384
    /// # use bevy::math::Vec3;
3385
    /// # let mut w = ExprWriter::new();
3386
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3387
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3388
    ///
3389
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3390
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3391
    ///
3392
    /// // The step value
3393
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3394
    /// ```
3395
    #[allow(clippy::should_implement_trait)]
3396
    #[inline]
3397
    pub fn step(self, edge: Self) -> Self {
×
3398
        // Note: order is step(edge, x) but x.step(edge)
3399
        edge.binary_op(self, BinaryOperator::Step)
×
3400
    }
3401

3402
    /// Subtract another expression from the current expression.
3403
    ///
3404
    /// This is a binary operator, which applies component-wise to vector
3405
    /// operand expressions.
3406
    ///
3407
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3408
    /// symbol, as an alternative to calling this method directly.
3409
    ///
3410
    /// # Example
3411
    ///
3412
    /// ```
3413
    /// # use bevy_hanabi::*;
3414
    /// # use bevy::math::Vec2;
3415
    /// # let mut w = ExprWriter::new();
3416
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3417
    /// let x = w.lit(Vec2::new(3., -2.));
3418
    ///
3419
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3420
    /// let y = w.lit(Vec2::new(1., 5.));
3421
    ///
3422
    /// // The difference of both vectors `z = x - y;`.
3423
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3424
    ///                   // -OR-
3425
    ///                   // let z = x - y;
3426
    /// ```
3427
    #[allow(clippy::should_implement_trait)]
3428
    #[inline]
3429
    pub fn sub(self, other: Self) -> Self {
×
3430
        self.binary_op(other, BinaryOperator::Sub)
×
3431
    }
3432

3433
    /// Apply the logical operator "uniform" to this expression and another
3434
    /// expression.
3435
    ///
3436
    /// This is a binary operator, which applies component-wise to vector
3437
    /// operand expressions. That is, for vectors, this produces a vector of
3438
    /// random values where each component is uniformly distributed within the
3439
    /// bounds of the related component of both operands.
3440
    ///
3441
    /// # Example
3442
    ///
3443
    /// ```
3444
    /// # use bevy_hanabi::*;
3445
    /// # use bevy::math::Vec3;
3446
    /// # let mut w = ExprWriter::new();
3447
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3448
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3449
    ///
3450
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3451
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3452
    ///
3453
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3454
    /// let z = x.uniform(y);
3455
    /// ```
3456
    #[inline]
3457
    pub fn uniform(self, other: Self) -> Self {
×
3458
        self.binary_op(other, BinaryOperator::UniformRand)
×
3459
    }
3460

3461
    /// Apply the logical operator "normal" to this expression and another
3462
    /// expression.
3463
    ///
3464
    /// This is a binary operator, which applies component-wise to vector
3465
    /// operand expressions. That is, for vectors, this produces a vector of
3466
    /// random values where each component is normally distributed with a mean
3467
    /// of the corresponding component of the first operand and a standard
3468
    /// deviation of the corresponding component of the second operand.
3469
    ///
3470
    /// # Example
3471
    ///
3472
    /// ```
3473
    /// # use bevy_hanabi::*;
3474
    /// # use bevy::math::Vec3;
3475
    /// # let mut w = ExprWriter::new();
3476
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3477
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3478
    ///
3479
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3480
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3481
    ///
3482
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3483
    /// let z = x.normal(y);
3484
    /// ```
3485
    #[inline]
3486
    pub fn normal(self, other: Self) -> Self {
×
3487
        self.binary_op(other, BinaryOperator::NormalRand)
×
3488
    }
3489

3490
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3491
        assert_eq!(self.module, second.module);
×
3492
        assert_eq!(self.module, third.module);
×
3493
        let first = self.expr;
×
3494
        let second = second.expr;
×
3495
        let third = third.expr;
×
3496
        let expr = self.module.borrow_mut().push(Expr::Ternary {
×
3497
            op,
×
3498
            first,
×
3499
            second,
×
3500
            third,
×
3501
        });
3502
        WriterExpr {
3503
            expr,
3504
            module: self.module,
×
3505
        }
3506
    }
3507

3508
    /// Blending linearly ("mix") two expressions with the fraction provided by
3509
    /// a third expression.
3510
    ///
3511
    /// This is a ternary operator, which applies component-wise to vector
3512
    /// operand expressions.
3513
    ///
3514
    /// # Example
3515
    ///
3516
    /// ```
3517
    /// # use bevy_hanabi::*;
3518
    /// # use bevy::math::Vec2;
3519
    /// # let mut w = ExprWriter::new();
3520
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3521
    /// let x = w.lit(Vec2::new(3., -2.));
3522
    ///
3523
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3524
    /// let y = w.lit(Vec2::new(1., 4.));
3525
    ///
3526
    /// // A fraction `t = 0.5;`.
3527
    /// let t = w.lit(0.25);
3528
    ///
3529
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3530
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3531
    /// ```
3532
    #[inline]
3533
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3534
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3535
    }
3536

3537
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3538
    /// value taken between the given bounds.
3539
    ///
3540
    /// This is a ternary operator, which applies component-wise to vector
3541
    /// operand expressions.
3542
    ///
3543
    /// # Example
3544
    ///
3545
    /// ```
3546
    /// # use bevy_hanabi::*;
3547
    /// # use bevy::math::Vec2;
3548
    /// # let mut w = ExprWriter::new();
3549
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3550
    /// let low = w.lit(Vec2::new(3., -2.));
3551
    ///
3552
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3553
    /// let high = w.lit(Vec2::new(1., 4.));
3554
    ///
3555
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3556
    /// let x = w.lit(Vec2::new(2., 1.));
3557
    ///
3558
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3559
    /// let t = x.smoothstep(low, high); // == 0.5
3560
    /// ```
3561
    #[inline]
3562
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3563
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3564
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3565
    }
3566

3567
    /// Construct a `Vec2` from two scalars.
3568
    ///
3569
    /// # Example
3570
    ///
3571
    /// ```
3572
    /// # use bevy_hanabi::*;
3573
    /// # let mut w = ExprWriter::new();
3574
    /// let theta = w.add_property("theta", 0.0.into());
3575
    /// // Convert the angular property `theta` to a 2D vector.
3576
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3577
    /// let circle_pos = cos_theta.vec2(sin_theta);
3578
    /// ```
3579
    #[inline]
3580
    pub fn vec2(self, y: Self) -> Self {
×
3581
        self.binary_op(y, BinaryOperator::Vec2)
×
3582
    }
3583

3584
    /// Construct a `Vec3` from two scalars.
3585
    ///
3586
    /// # Example
3587
    ///
3588
    /// ```
3589
    /// # use bevy_hanabi::*;
3590
    /// # let mut w = ExprWriter::new();
3591
    /// let theta = w.add_property("theta", 0.0.into());
3592
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
3593
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3594
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
3595
    /// ```
3596
    #[inline]
3597
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
3598
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
3599
    }
3600

3601
    /// Cast an expression to a different type.
3602
    ///
3603
    /// # Example
3604
    ///
3605
    /// ```
3606
    /// # use bevy_hanabi::*;
3607
    /// # use bevy::math::Vec2;
3608
    /// # let mut w = ExprWriter::new();
3609
    /// let x = w.lit(Vec2::new(3., -2.));
3610
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
3611
    /// ```
3612
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
3613
        let target = target.into();
×
3614
        let expr = self
×
3615
            .module
×
3616
            .borrow_mut()
3617
            .push(Expr::Cast(CastExpr::new(self.expr, target)));
×
3618
        WriterExpr {
3619
            expr,
3620
            module: self.module,
×
3621
        }
3622
    }
3623

3624
    /// Finalize an expression chain and return the accumulated expression.
3625
    ///
3626
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
3627
    /// this intermediate expression was built from.
3628
    ///
3629
    /// # Example
3630
    ///
3631
    /// ```
3632
    /// # use bevy_hanabi::*;
3633
    /// # let mut w = ExprWriter::new();
3634
    /// // A literal expression `x = -3.5;`.
3635
    /// let x = w.lit(-3.5);
3636
    ///
3637
    /// // Retrieve the ExprHandle for that expression.
3638
    /// let handle = x.expr();
3639
    /// ```
3640
    #[inline]
3641
    pub fn expr(self) -> ExprHandle {
8✔
3642
        self.expr
8✔
3643
    }
3644
}
3645

3646
impl std::ops::Add<WriterExpr> for WriterExpr {
3647
    type Output = WriterExpr;
3648

3649
    #[inline]
3650
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
3651
        self.add(rhs)
2✔
3652
    }
3653
}
3654

3655
impl std::ops::Sub<WriterExpr> for WriterExpr {
3656
    type Output = WriterExpr;
3657

3658
    #[inline]
3659
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
3660
        self.sub(rhs)
×
3661
    }
3662
}
3663

3664
impl std::ops::Mul<WriterExpr> for WriterExpr {
3665
    type Output = WriterExpr;
3666

3667
    #[inline]
3668
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
3669
        self.mul(rhs)
1✔
3670
    }
3671
}
3672

3673
impl std::ops::Div<WriterExpr> for WriterExpr {
3674
    type Output = WriterExpr;
3675

3676
    #[inline]
3677
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
3678
        self.div(rhs)
×
3679
    }
3680
}
3681

3682
impl std::ops::Rem<WriterExpr> for WriterExpr {
3683
    type Output = WriterExpr;
3684

3685
    #[inline]
3686
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
3687
        self.rem(rhs)
×
3688
    }
3689
}
3690

3691
#[cfg(test)]
3692
mod tests {
3693
    use bevy::{prelude::*, utils::HashSet};
3694

3695
    use super::*;
3696
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
3697

3698
    #[test]
3699
    fn module() {
3700
        let mut m = Module::default();
3701

3702
        #[allow(unsafe_code)]
3703
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
3704
        assert!(m.get(unknown).is_none());
3705
        assert!(m.get_mut(unknown).is_none());
3706
        assert!(matches!(
3707
            m.try_get(unknown),
3708
            Err(ExprError::InvalidExprHandleError(_))
3709
        ));
3710
        assert!(matches!(
3711
            m.try_get_mut(unknown),
3712
            Err(ExprError::InvalidExprHandleError(_))
3713
        ));
3714

3715
        let x = m.lit(5.);
3716
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
3717
        assert_eq!(m.get(x), Some(&expected));
3718
        assert_eq!(m.get_mut(x), Some(&mut expected));
3719
        assert_eq!(m.try_get(x), Ok(&expected));
3720
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
3721
    }
3722

3723
    #[test]
3724
    fn local_var() {
3725
        let property_layout = PropertyLayout::default();
3726
        let particle_layout = ParticleLayout::default();
3727
        let mut ctx =
3728
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3729
        let mut h = HashSet::new();
3730
        for _ in 0..100 {
3731
            let v = ctx.make_local_var();
3732
            assert!(h.insert(v));
3733
        }
3734
    }
3735

3736
    #[test]
3737
    fn make_fn() {
3738
        let property_layout = PropertyLayout::default();
3739
        let particle_layout = ParticleLayout::default();
3740
        let mut ctx =
3741
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3742
        let mut module = Module::default();
3743

3744
        // Make a function
3745
        let func_name = "my_func";
3746
        let args = "arg0: i32, arg1: f32";
3747
        assert!(ctx
3748
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
3749
                m.lit(3.);
3750
                let v = ctx.make_local_var();
3751
                assert_eq!(v, "var0");
3752
                let code = String::new();
3753
                Ok(code)
3754
            })
3755
            .is_ok());
3756

3757
        // The local function context doesn't influence the outer caller context
3758
        let v = ctx.make_local_var();
3759
        assert_eq!(v, "var0");
3760

3761
        // However the module is common to the outer caller and the function
3762
        assert!(!module.expressions.is_empty());
3763
    }
3764

3765
    #[test]
3766
    fn property() {
3767
        let mut m = Module::default();
3768

3769
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
3770
        let _other_prop = m.add_property(
3771
            "other_prop",
3772
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
3773
        );
3774

3775
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
3776
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
3777
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
3778
    }
3779

3780
    #[test]
3781
    fn writer() {
3782
        // Get a module and its writer
3783
        let w = ExprWriter::new();
3784
        let my_prop = w.add_property("my_prop", 3.0.into());
3785

3786
        // Build some expression
3787
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
3788
            + w.lit(-4.).min(w.prop(my_prop));
3789
        let x = x.expr();
3790

3791
        // Create an evaluation context
3792
        let property_layout =
3793
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
3794
        let particle_layout = ParticleLayout::default();
3795
        let m = w.finish();
3796
        let mut context =
3797
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3798

3799
        // Evaluate the expression
3800
        let x = m.try_get(x).unwrap();
3801
        let s = x.eval(&m, &mut context).unwrap();
3802
        assert_eq!(
3803
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties.my_prop))"
3804
                .to_string(),
3805
            s
3806
        );
3807
    }
3808

3809
    #[test]
3810
    fn type_error() {
3811
        let l = Value::Scalar(3.5_f32.into());
3812
        let r: Result<Vec2, ExprError> = l.try_into();
3813
        assert!(r.is_err());
3814
        assert!(matches!(r, Err(ExprError::TypeError(_))));
3815
    }
3816

3817
    #[test]
3818
    fn math_expr() {
3819
        let mut m = Module::default();
3820

3821
        let x = m.attr(Attribute::POSITION);
3822
        let y = m.lit(Vec3::ONE);
3823

3824
        let add = m.add(x, y);
3825
        let sub = m.sub(x, y);
3826
        let mul = m.mul(x, y);
3827
        let div = m.div(x, y);
3828
        let rem = m.rem(x, y);
3829
        let lt = m.lt(x, y);
3830
        let le = m.le(x, y);
3831
        let gt = m.gt(x, y);
3832
        let ge = m.ge(x, y);
3833

3834
        let property_layout = PropertyLayout::default();
3835
        let particle_layout = ParticleLayout::default();
3836
        let mut ctx =
3837
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3838

3839
        for (expr, op) in [
3840
            (add, "+"),
3841
            (sub, "-"),
3842
            (mul, "*"),
3843
            (div, "/"),
3844
            (rem, "%"),
3845
            (lt, "<"),
3846
            (le, "<="),
3847
            (gt, ">"),
3848
            (ge, ">="),
3849
        ] {
3850
            let expr = ctx.eval(&m, expr);
3851
            assert!(expr.is_ok());
3852
            let expr = expr.unwrap();
3853
            assert_eq!(
3854
                expr,
3855
                format!(
3856
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
3857
                    Attribute::POSITION.name(),
3858
                    op,
3859
                )
3860
            );
3861
        }
3862
    }
3863

3864
    #[test]
3865
    fn builtin_expr() {
3866
        let mut m = Module::default();
3867

3868
        // Simulation parameters
3869
        for op in [
3870
            BuiltInOperator::Time,
3871
            BuiltInOperator::DeltaTime,
3872
            BuiltInOperator::VirtualTime,
3873
            BuiltInOperator::VirtualDeltaTime,
3874
            BuiltInOperator::RealTime,
3875
            BuiltInOperator::RealDeltaTime,
3876
        ] {
3877
            let value = m.builtin(op);
3878

3879
            let property_layout = PropertyLayout::default();
3880
            let particle_layout = ParticleLayout::default();
3881
            let mut ctx =
3882
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3883

3884
            let expr = ctx.eval(&m, value);
3885
            assert!(expr.is_ok());
3886
            let expr = expr.unwrap();
3887
            assert_eq!(expr, format!("sim_params.{}", op.name()));
3888
        }
3889

3890
        // is_alive
3891
        {
3892
            let value = m.builtin(BuiltInOperator::IsAlive);
3893

3894
            let property_layout = PropertyLayout::default();
3895
            let particle_layout = ParticleLayout::default();
3896
            let mut ctx =
3897
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3898

3899
            let expr = ctx.eval(&m, value);
3900
            assert!(expr.is_ok());
3901
            let expr = expr.unwrap();
3902
            assert_eq!(expr, "is_alive");
3903
        }
3904

3905
        // BuiltInOperator::Rand (which has side effect)
3906
        for (scalar_type, prefix) in [
3907
            (ScalarType::Bool, "b"),
3908
            (ScalarType::Float, "f"),
3909
            (ScalarType::Int, "i"),
3910
            (ScalarType::Uint, "u"),
3911
        ] {
3912
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
3913

3914
            // Scalar form
3915
            {
3916
                let property_layout = PropertyLayout::default();
3917
                let particle_layout = ParticleLayout::default();
3918
                let mut ctx =
3919
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3920

3921
                let expr = ctx.eval(&m, value);
3922
                assert!(expr.is_ok());
3923
                let expr = expr.unwrap();
3924
                assert_eq!(expr, "var0");
3925
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
3926
            }
3927

3928
            // Vector form
3929
            for count in 2..=4 {
3930
                let vec = m.builtin(BuiltInOperator::Rand(
3931
                    VectorType::new(scalar_type, count).into(),
3932
                ));
3933

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

3939
                let expr = ctx.eval(&m, vec);
3940
                assert!(expr.is_ok());
3941
                let expr = expr.unwrap();
3942
                assert_eq!(expr, "var0");
3943
                assert_eq!(
3944
                    ctx.main_code,
3945
                    format!("let var0 = {}rand{}();\n", prefix, count)
3946
                );
3947
            }
3948
        }
3949
    }
3950

3951
    #[test]
3952
    fn unary_expr() {
3953
        let mut m = Module::default();
3954

3955
        let x = m.attr(Attribute::POSITION);
3956
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
3957
        let z = m.lit(BVec3::new(false, true, false));
3958
        let w = m.lit(Vec4::W);
3959
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
3960
        let us = m.lit(0x0u32);
3961
        let uu = m.lit(0x0u32);
3962

3963
        let abs = m.abs(x);
3964
        let all = m.all(z);
3965
        let any = m.any(z);
3966
        let ceil = m.ceil(y);
3967
        let cos = m.cos(y);
3968
        let exp = m.exp(y);
3969
        let exp2 = m.exp2(y);
3970
        let floor = m.floor(y);
3971
        let fract = m.fract(y);
3972
        let inv_sqrt = m.inverse_sqrt(y);
3973
        let length = m.length(y);
3974
        let log = m.log(y);
3975
        let log2 = m.log2(y);
3976
        let norm = m.normalize(y);
3977
        let pack4x8snorm = m.pack4x8snorm(v);
3978
        let pack4x8unorm = m.pack4x8unorm(v);
3979
        let saturate = m.saturate(y);
3980
        let sign = m.sign(y);
3981
        let sin = m.sin(y);
3982
        let sqrt = m.sqrt(y);
3983
        let tan = m.tan(y);
3984
        let unpack4x8snorm = m.unpack4x8snorm(us);
3985
        let unpack4x8unorm = m.unpack4x8unorm(uu);
3986
        let comp_x = m.x(w);
3987
        let comp_y = m.y(w);
3988
        let comp_z = m.z(w);
3989
        let comp_w = m.w(w);
3990

3991
        let property_layout = PropertyLayout::default();
3992
        let particle_layout = ParticleLayout::default();
3993
        let mut ctx =
3994
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3995

3996
        for (expr, op, inner) in [
3997
            (
3998
                abs,
3999
                "abs",
4000
                &format!("particle.{}", Attribute::POSITION.name())[..],
4001
            ),
4002
            (all, "all", "vec3<bool>(false,true,false)"),
4003
            (any, "any", "vec3<bool>(false,true,false)"),
4004
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
4005
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
4006
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
4007
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
4008
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
4009
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
4010
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
4011
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
4012
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
4013
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
4014
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
4015
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4016
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
4017
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4018
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4019
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4020
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4021
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4022
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4023
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4024
        ] {
4025
            let expr = ctx.eval(&m, expr);
4026
            assert!(expr.is_ok());
4027
            let expr = expr.unwrap();
4028
            assert_eq!(expr, format!("{}({})", op, inner));
4029
        }
4030

4031
        for (expr, op, inner) in [
4032
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4033
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4034
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4035
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4036
        ] {
4037
            let expr = ctx.eval(&m, expr);
4038
            assert!(expr.is_ok());
4039
            let expr = expr.unwrap();
4040
            assert_eq!(expr, format!("{}.{}", inner, op));
4041
        }
4042
    }
4043

4044
    #[test]
4045
    fn binary_expr() {
4046
        let mut m = Module::default();
4047

4048
        let x = m.attr(Attribute::POSITION);
4049
        let y = m.lit(Vec3::ONE);
4050

4051
        let cross = m.cross(x, y);
4052
        let dist = m.distance(x, y);
4053
        let dot = m.dot(x, y);
4054
        let min = m.min(x, y);
4055
        let max = m.max(x, y);
4056
        let step = m.step(x, y);
4057

4058
        let property_layout = PropertyLayout::default();
4059
        let particle_layout = ParticleLayout::default();
4060
        let mut ctx =
4061
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4062

4063
        for (expr, op) in [
4064
            (cross, "cross"),
4065
            (dist, "distance"),
4066
            (dot, "dot"),
4067
            (min, "min"),
4068
            (max, "max"),
4069
            (step, "step"),
4070
        ] {
4071
            let expr = ctx.eval(&m, expr);
4072
            assert!(expr.is_ok());
4073
            let expr = expr.unwrap();
4074
            assert_eq!(
4075
                expr,
4076
                format!(
4077
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4078
                    op,
4079
                    Attribute::POSITION.name(),
4080
                )
4081
            );
4082
        }
4083
    }
4084

4085
    #[test]
4086
    fn ternary_expr() {
4087
        let mut m = Module::default();
4088

4089
        let x = m.attr(Attribute::POSITION);
4090
        let y = m.lit(Vec3::ONE);
4091
        let t = m.lit(0.3);
4092

4093
        let mix = m.mix(x, y, t);
4094
        let smoothstep = m.smoothstep(x, y, x);
4095

4096
        let property_layout = PropertyLayout::default();
4097
        let particle_layout = ParticleLayout::default();
4098
        let mut ctx =
4099
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4100

4101
        for (expr, op, third) in [(mix, "mix", t), (smoothstep, "smoothstep", x)] {
4102
            let expr = ctx.eval(&m, expr);
4103
            assert!(expr.is_ok());
4104
            let expr = expr.unwrap();
4105
            let third = ctx.eval(&m, third).unwrap();
4106
            assert_eq!(
4107
                expr,
4108
                format!(
4109
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4110
                    op,
4111
                    Attribute::POSITION.name(),
4112
                    third
4113
                )
4114
            );
4115
        }
4116
    }
4117

4118
    #[test]
4119
    fn cast_expr() {
4120
        let mut m = Module::default();
4121

4122
        let x = m.attr(Attribute::POSITION);
4123
        let y = m.lit(IVec2::ONE);
4124
        let z = m.lit(0.3);
4125
        let w = m.lit(false);
4126

4127
        let cx = m.cast(x, VectorType::VEC3I);
4128
        let cy = m.cast(y, VectorType::VEC2U);
4129
        let cz = m.cast(z, ScalarType::Int);
4130
        let cw = m.cast(w, ScalarType::Uint);
4131

4132
        let property_layout = PropertyLayout::default();
4133
        let particle_layout = ParticleLayout::default();
4134
        let mut ctx =
4135
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4136

4137
        for (expr, cast, target) in [
4138
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4139
            (y, cy, VectorType::VEC2U.into()),
4140
            (z, cz, ScalarType::Int.into()),
4141
            (w, cw, ScalarType::Uint.into()),
4142
        ] {
4143
            let expr = ctx.eval(&m, expr);
4144
            assert!(expr.is_ok());
4145
            let expr = expr.unwrap();
4146
            let cast = ctx.eval(&m, cast);
4147
            assert!(cast.is_ok());
4148
            let cast = cast.unwrap();
4149
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4150
        }
4151
    }
4152

4153
    #[test]
4154
    fn attribute_pointer() {
4155
        let mut m = Module::default();
4156
        let x = m.attr(Attribute::POSITION);
4157

4158
        let property_layout = PropertyLayout::default();
4159
        let particle_layout = ParticleLayout::default();
4160
        let mut ctx =
4161
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4162

4163
        let res = ctx.eval(&m, x);
4164
        assert!(res.is_ok());
4165
        let xx = res.ok().unwrap();
4166
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4167

4168
        // Use a different context; it's invalid to reuse a mutated context, as the
4169
        // expression cache will have been generated with the wrong context.
4170
        let mut ctx =
4171
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4172
                .with_attribute_pointer();
4173

4174
        let res = ctx.eval(&m, x);
4175
        assert!(res.is_ok());
4176
        let xx = res.ok().unwrap();
4177
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4178
    }
4179

4180
    #[test]
4181
    #[should_panic]
4182
    fn invalid_cast_vector_to_scalar() {
4183
        let mut m = Module::default();
4184
        let x = m.lit(Vec2::ONE);
4185
        let _ = m.cast(x, ScalarType::Float);
4186
    }
4187

4188
    #[test]
4189
    #[should_panic]
4190
    fn invalid_cast_matrix_to_scalar() {
4191
        let mut m = Module::default();
4192
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4193
        let _ = m.cast(x, ScalarType::Float);
4194
    }
4195

4196
    #[test]
4197
    #[should_panic]
4198
    fn invalid_cast_matrix_to_vector() {
4199
        let mut m = Module::default();
4200
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4201
        let _ = m.cast(x, VectorType::VEC4F);
4202
    }
4203

4204
    #[test]
4205
    #[should_panic]
4206
    fn invalid_cast_scalar_to_matrix() {
4207
        let mut m = Module::default();
4208
        let x = m.lit(3.);
4209
        let _ = m.cast(x, MatrixType::MAT3X3F);
4210
    }
4211

4212
    #[test]
4213
    #[should_panic]
4214
    fn invalid_cast_vector_to_matrix() {
4215
        let mut m = Module::default();
4216
        let x = m.lit(Vec3::ZERO);
4217
        let _ = m.cast(x, MatrixType::MAT2X4F);
4218
    }
4219

4220
    #[test]
4221
    fn cast_expr_new() {
4222
        let mut m = Module::default();
4223

4224
        let x = m.attr(Attribute::POSITION);
4225
        let c = CastExpr::new(x, VectorType::VEC3F);
4226
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4227
        assert_eq!(c.is_valid(&m), Some(true));
4228

4229
        let x = m.attr(Attribute::POSITION);
4230
        let c = CastExpr::new(x, ScalarType::Bool);
4231
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4232
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4233

4234
        let p = m.add_property("my_prop", 3.0.into());
4235
        let y = m.prop(p);
4236
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4237
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4238
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4239
    }
4240

4241
    #[test]
4242
    fn side_effect() {
4243
        let mut m = Module::default();
4244

4245
        // Adding the same cloned expression with side effect to itself should yield
4246
        // twice the value, and not two separate evaluations of the expression.
4247
        // CORRECT:
4248
        //   let r = frand();
4249
        //   r + r
4250
        // INCORRECT:
4251
        //   frand() + frand()
4252

4253
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4254
        let r2 = r;
4255
        let r3 = r2;
4256
        let a = m.add(r, r2);
4257
        let b = m.mix(r, r2, r3);
4258
        let c = m.abs(a);
4259

4260
        {
4261
            let property_layout = PropertyLayout::default();
4262
            let particle_layout = ParticleLayout::default();
4263
            let mut ctx =
4264
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4265
            let value = ctx.eval(&m, a).unwrap();
4266
            assert_eq!(value, "(var0) + (var0)");
4267
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4268
        }
4269

4270
        {
4271
            let property_layout = PropertyLayout::default();
4272
            let particle_layout = ParticleLayout::default();
4273
            let mut ctx =
4274
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4275
            let value = ctx.eval(&m, b).unwrap();
4276
            assert_eq!(value, "mix(var0, var0, var0)");
4277
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4278
        }
4279

4280
        {
4281
            let property_layout = PropertyLayout::default();
4282
            let particle_layout = ParticleLayout::default();
4283
            let mut ctx =
4284
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4285
            let value = ctx.eval(&m, c).unwrap();
4286
            assert_eq!(value, "abs((var0) + (var0))");
4287
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4288
        }
4289
    }
4290

4291
    // #[test]
4292
    // fn serde() {
4293
    //     let v = Value::Scalar(3.0_f32.into());
4294
    //     let l: LiteralExpr = v.into();
4295
    //     assert_eq!(Ok(v), l.eval());
4296
    //     let s = ron::to_string(&l).unwrap();
4297
    //     println!("literal: {:?}", s);
4298
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4299
    //     assert_eq!(l_serde, l);
4300

4301
    //     let b: ExprHandle = Box::new(l);
4302
    //     let s = ron::to_string(&b).unwrap();
4303
    //     println!("boxed literal: {:?}", s);
4304
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4305
    //     assert!(b_serde.is_const());
4306
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4307

4308
    //     let v0 = Value::Scalar(3.0_f32.into());
4309
    //     let v1 = Value::Scalar(2.5_f32.into());
4310
    //     let l0: LiteralExpr = v0.into();
4311
    //     let l1: LiteralExpr = v1.into();
4312
    //     let a = l0 + l1;
4313
    //     assert!(a.is_const());
4314
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4315
    //     let s = ron::to_string(&a).unwrap();
4316
    //     println!("add: {:?}", s);
4317
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4318
    //     println!("a_serde: {:?}", a_serde);
4319
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4320
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4321
    // }
4322
}
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